input:
4
5 15
13 37
8 9
10009 20000
output:
0
1
-1
79
题目大意:
如果一个数对(x,y)是幸运的,当且仅当gcd(x,y)=1,一条链可以由以下规律的数对组成,(x,y),(x+1,y+1),(x+2,y+2)……(x+k,y+k),如果说一条链是幸运的,当且仅当这条链上的每一个数对都是幸运的,每次给出一个数对,问这个以这个数对为一条链的起点,所能构成的幸运链的长度最长是多少?如果说这条链的长度是无穷的,输出-1,否则输出链的长度。
解题思路:
gcd(a,b)=gcd(a,a-b),(a>b),至于为什么,可参考以下网址证明gcd(a,b)=gcd(a-b,b) - Dance With Automation - 博客园 (cnblogs.com)
gcd(a+k,b+k)=gcd(a+k,b-a)=1
所以我们最终的任务就是找到一个(b-a)的因子k,使得k-a%k最小,由于a,b都是固定的,所以我们我们每次找到b-a的最小质因子p(该过程可以通过筛素数的过程得到),然后用p-a%p去更新答案即可,当一个因子用完以后,把这个因子从(b-a)中除尽,然后再考虑下一个因子。
上代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e7+10;
int maxn=1e7+10;
//p[i]表示i的最小质因子,primes[i]表示第i个质数
int p[N],primes[N],f[N];
int cnt=0;
void getprimes()
{
primes[1]=1;
for(int i=2;i<N;i++)
{
if(!f[i])
primes[++cnt]=i,p[i]=i;//如果i在之前未被标记,那i就一定是质数
//s[i]记录的是i这个数字的最小质因子
for(int j=1;j<=cnt;j++)
{
if(i*primes[j]>=N)//如果当前得到的数字超出了范围直接break
break;
f[i*primes[j]]=1;//素数的倍数一定不是素数,可以直接标记
p[i*primes[j]]=primes[j];
if(i%primes[j]==0)//这句话是欧拉筛的精髓,如果i能被p[j]整除,那么在之后的i*p[j+1]....都会被p[j]*一个数所标记
// 现在来证明一下:当i是p[j]的整数倍的时候,记m=i/p[j],则i*p[j+1]=m*p[j+1]*p[j],说明i*p[j+1]是p[j]的倍数吗,不需要再进行标记 (在之后会被 prime[j] *某个数(m*prime[j+1])标记),
//对于 prime[j+2] 及之后的素数同理,直接跳出循环,这样就避免了重复标记。
break;
}
}
// p[0] = p[1] = -1;
// for (int i = 2; i < maxn; i++)
// {
// if (!p[i])
// primes[++cnt] = i, p[i] = i;
// for (int j = 1; j <= cnt && primes[j] * i < maxn; j++)
// {
// p[i * primes[j]] = primes[j];
// if (i % primes[j] == 0)
// break;
// }
// }
}
int main()
{
//一定要加关闭流同步这两行代码,否则必T在第二个点上
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int t;
getprimes();
cin>>t;
while(t--)
{
int x,y;
cin>>x>>y;
if(abs(x-y)==1)//如果说两个数字相差1,那么这两个数字永远互质
{
cout<<"-1"<<endl;
continue;
}
if(__gcd(x,y)!=1)
{
cout<<"0"<<endl;
continue;
}
int c=abs(x-y);
int ans=0x3f3f3f3f;
while(c>1)
{
ans=min(ans,p[c]-x%p[c]);
int temp=p[c];
while(c%temp==0)
c/=temp;
}
cout<<ans<<endl;
}
return 0;
}