[Math×Girl] 距离 - Official题解
距离
观前提醒
本题利用几何有更直观的做法,详见我用 desmos 画的。
不过为了严谨性,你可以结合着看下面的步骤。
思路分析
部分分
设
我们要最小化
令
若
确定了
有:
再根据
为了确保答案的正确性,我们可以枚举所有的:
时间复杂度为
若
确定了
有:
再根据
为了确保答案的正确性,我们可以枚举所有的:
时间复杂度为
合并做法
若
这样的时间复杂度是
这何尝又不是一种分治。
但是这题的
时间复杂度
※ 这一部分内容可以没必要看,毕竟这是信息学(雾)。
我们以概率的方法分析
为了分析简单,我们只统计满足
确定了
可以发现
假设其是均匀且独立分布随机变量
※ 可能会有一定程度上的误差,这里无伤大雅。
可以发现我们时间复杂度最大时是
这时
但是
于是我们可以认为时间复杂度的上界为
当然,如果你想更精确的分析这个时间复杂度也可以,
我们设最坏概率为
更进一步的分析可以发现这个算法的时间复杂度是极快的,这里就不写了。
代码实现
工程细节
如果你真的把
我们可以取
具体实现方法和更多细节可以看代码。
出题人代码
#include<bits/stdc++.h>
typedef long long i8;
i8 T,x,y;
i8 ydis(i8 ty){
i8 kc=x/ty+1,xc=kc*ty,c=abs(ty-y)+abs(xc-x);
i8 kf=x/ty ,xf=kf*ty,f=abs(ty-y)+abs(xf-x);
return std::min(c,f);
}i8 ysolve(){
i8 ans=ydis(y);
for(i8 t=1;t<ans;t++)
ans=std::min(ans,ydis(y-t)),
ans=std::min(ans,ydis(y+t));
return ans;
}
i8 kdis(i8 k){
i8 yc=x/k+1,xc=k*yc,c=abs(yc-y)+abs(xc-x);
i8 yf=x/k ,xf=k*yf,f=abs(yf-y)+abs(xf-x);
return std::min(c,f);
}i8 ksolve(){
i8 ans=kdis(x/y);
for(i8 t=1;abs(1.0*x/(x/y-t)-y)<ans;t++)
ans=std::min(ans,kdis(x/y-t));
for(i8 t=1;abs(1.0*x/(x/y+t)-y)<ans;t++)
ans=std::min(ans,kdis(x/y+t));
return ans;
}
int main(){
std::cin>>T;
while(T--){std::cin>>x>>y;
if(x<y)std::swap(x,y);
std::cout<<(y<x/y?ysolve():ksolve())<<"\n";
}return 0;
}
验题人代码
#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
ll x, y;
ll GetDistY(ll yy){
ll ka = x / yy, xa = ka * yy;
ll kb = x / yy + 1, xb = kb * yy;
return min(abs(xa - x), abs(xb - x)) + abs(yy - y);
}
ll GetDistK(ll k){
ll ya = x / k, xa = k * ya;
ll yb = x / k + 1, xb = k * yb;
return min(abs(xa - x) + abs(ya - y), abs(xb - x) + abs(yb - y));
}
ll Solve(){
if(x < y) swap(x, y);
if(x % y == 0) return 0;
ll ans = 114514 + 1919810;
if(y <= x / y){
ans = GetDistY(y);
for(ll i = 1; i < ans; ++i) ans = min(ans, min(GetDistY(y + i), GetDistY(y - i)));
}
else{
ans = GetDistK(x / y);
for(ll i = x / y + 1; y - 1.0L * x / i < ans; ++i) ans = min(ans, GetDistK(i));
for(ll i = x / y - 1; 1.0L * x / i - y < ans; --i) ans = min(ans, GetDistK(i));
}
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T; cin >> T;
while(T--){
cin >> x >> y;
cout << Solve() << endl;
}
return 0;
}