分析
每次输入a,b,c,k
询问a是否能通过+c得到b(k循环条件下)
a+cx≡b mod 2k a+cx\equiv b \bmod 2^{k} a+cx≡bmod2k
上式等价于:
cx−2ky=b−a cx-2^{k}y=b-a cx−2ky=b−a 令z=2^{k}得到:
cx−zy=b−a cx-zy=b-a cx−zy=b−a
因为要求 x,y 两个未知量 因此使用扩展欧几里得算法exgcd(c,z,x,y)
求出d:d=exgcd(c,z,x,y)(d为(c,z)最大公约数)d=exgcd(c,z,x,y)(d为(c,z)最大公约数)d=exgcd(c,z,x,y)(d为(c,z)最大公约数)
(b-a)如果不为d的倍数,说明不存在这样一个解,输出"FOREVER"
(b-a)为d的倍数的话,要把x,y扩大相应倍数:
x=x⋅b−ad,y=y⋅b−ad x=x\cdot \frac{b-a}{d},y=y\cdot \frac{b-a}{d} x=x⋅db−a,y=y⋅db−a
此时要求出解x,x等价于:x=x0+kzd x=x_{0}+k\frac{z}{d} x=x0+kdz
最小的x等价于求x的正余数:(x%z + z) % z
C++ 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a,b,c,k;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
LL d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
while(cin>>a>>b>>c>>k,a||b||c||k)
{
LL x,y;
LL z=(1ll<<k);
LL d=exgcd(c,z,x,y);
cout<<(b-a)<<" "<<d<<endl;
if((b-a)%d) puts("FOREVER"); //(b-a)不是d的倍数,直接退出
else{
x*=(b-a)/d;
y*=(b-a)/d;
z/=d;
cout<<(x%z+z)%z<<endl; //求最小正余数
}
}
return 0;
}