题目
这里有一个性质,对于互质的两个数 a , b a,b a,b,它们的答案与 a g , b g ag,bg ag,bg 两数的答案相等。设 a g , b g ag,bg ag,bg 第 i i i 操作减去的数 x x x; a , b a,b a,b 第 i i i 次操作减去的数为 y y y,显然有 x = g y x=gy x=gy,前者减去的数是后者的 g g g 倍,而 a g , b g ag,bg ag,bg 又恰好是 a , b a,b a,b 的 g g g 倍,得证。
所以我们可以先把 a , b a,b a,b 除以其最大公约数,变成互质的 a , b a,b a,b。此时最大公约数是 1 1 1,如果后面的最大公约数一直是 1 1 1,直接模拟必然超时。
对于特殊情况:如果 a = b a=b a=b,步数为 1 1 1;如果 a , b a,b a,b 有一者为 1 1 1,步数为 1 1 1;如果 ∣ a − b ∣ = 1 |a-b|=1 ∣a−b∣=1,步数为 min ( a , b ) \min(a,b) min(a,b)。
考虑一般情况:快速求出最小的 k k k,存在大于 1 1 1 的数 p p p 满足 gcd ( a − k , b − k ) = p \gcd(a-k,b-k)=p gcd(a−k,b−k)=p。显然限定 p p p 为质数不会增大 k k k。枚举 1 0 6 10^6 106 以内的质数求出最小的 k k k(注意 k < min ( a , b ) k<\min(a,b) k<min(a,b) 等细节),然后重复上面的流程即可。
分析时间复杂度:设 N = max ( A , B ) N=\max(A,B) N=max(A,B)求最小的 k k k 是 O ( N ln N ) O(\frac{\sqrt N}{\ln N}) O(lnNN ) 的,每次 a , b a,b a,b 都要除以最大公约数,因此会有 O ( log 2 N ) O(\log_2 N) O(log2N) 次流程,预处理质数 O ( N ) O(\sqrt N) O(N ),总的时间复杂度为 O ( N ) O(\sqrt N) O(N )。
#include
using namespace std;
#define ll long long
const int N=1e6+1;
ll n,m,ans;
int a[N],p[N],cnt;
ll gcd(ll a,ll b)
{
return !b?a:gcd(b,a%b);
}
int main()
{
a[1]=1;
for(int i=2;i<N;i++){
if(!a[i]) p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<N;j++){
a[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
cin>>n>>m;
while(n&&m){
if(n>m) swap(n,m);
ll g=gcd(n,m);
n/=g,m/=g;
if(abs(n-m)<=1) cout<<ans+min(n,m),exit(0);
ll k=1e12,P=0;
for(int i=1;i<=cnt&&p[i]<=n;i++) if(p[i]<=n&&n%p[i]==m%p[i]) k=min(k,n%p[i]);
if(k==1e12){
ll x=abs(n-m);
if(x<=n&&n%x==m%x) k=n%x;
else k=n;
}
ans+=k;
n-=k,m-=k;
}
cout<<ans;
}