执行了X次后
C*x+y*2^k=B-A
从A到B
本质就是求同余方程
C*x=B-A mod 2^k
注意k的范围是32,超过int了,全用longlong
接下来就是求同余方程那一套了
a*x+b*y=gcd(a,b)这个扩展欧几里德算法解出来的x是最小的
还有
第一步后,方程式变为
gcd=gcd(C,2^k)
C*x/gcd+y*2^k/gcd=(B-A)/gcd
(C*x)/gcd=(B-A)/gcd mod 2^k/gcd
这时候x可能得到负数,但是要在2^k/gcd范围内模成正数(道理很简单,C和2^k同时缩短gcd倍,步长和路程保持比例不变,步数是不变的),也是一个WA点。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
long long x,y;
void extend_Eulid(long long a,long long b){
if(b == 0){
x = 1;y = 0;
}else{
extend_Eulid(b,a%b);
long long temp = x;x = y;y = temp - a/b*y;
}
}
long long gcd(long long a,long long b)
{
if(a<b) swap(a,b);
return b==0?a:gcd(b,a%b);
}
long long ans;
long long k;
bool getLinerModualSolve(long long a,long long b,long long n)
{
long long origin_b=b;
long long tmp=gcd(a,b);
if(n%tmp!=0) return false;
a/=tmp;b/=tmp;n/=tmp;
extend_Eulid(a,b);
ans=x*n;
ans=(ans%b+b)%b;
return true;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("G:/1.txt","r",stdin);
freopen("G:/2.txt","w",stdout);
#endif
long long A,B,C;
while(cin>>A>>B>>C>>k)
{
if(!A&&!B&&!C&&!k)
return 0;
long long mod=(long long)1<<k;
if(getLinerModualSolve(C,mod,B-A))
{
printf("%lld\n",ans);
}
else
{
printf("FOREVER\n");
}
}
return 0;
}