题意: 持续循环, 直到A=B停止循环, 其中每次循环A的增量为C (A+=C), 要求数据%2^k(即但A+=C, A=A%2^k, 使得数据始终在0-2^k之间), 求是否A和B会相等;
若相等(第一次相等)则输出循环次数, 否则输出"FOREVER"`.
解:
按照题意可设循环次数为x, 循环过程中A大于2^k的次数为y;则方程为
(A+C*x)%2^k = B;
即 A + C*x = B + 2^k * y
令a = C, b = 2^k, c = B-A;
则上述方程可转变成:
a*x + b*y = c;
求解 x的最小整数解;(因为是输出第一次相等时候的循环次数, 所以求出的循环次数x一定是所有x的解中最小的正整数)
根据欧几里德算法可求出a, b的最大公约数 gcd, 以及关于方程 a*x0+b*y0=gcd (与上面的方程不同, 注意)中的一个特解.x0, y0
则通解方程为:
x = x0 + b/gcd * t; (因为是a*x, 代入便是 a* x0 + a*b/gcd)
y = y0 - a/gcd *t; (因为是b*y, 代入便是 b*y0 - b*a/gcd)
则要求解 a*X + b*Y = c; 只要上述通解x * c/gcd即可;(联立上述两个方程(a*x+b*y=gcd, a*X+b*Y=c 即可知道为何x*c/gcd为a*X+b*Y=c的解)
由于x求出来要求为最小整数解;故需要进行处理为:
第一步: x为 a*x+b*y = gcd(a, b)求出来的特解, 通过该特解去求出 a*X+b*Y = c的最小正整数解;
第二步: 将上述 x*c/gcd可得到a*X+b*Y = c的一个解X = x*c/gcd;
第三步: X = X%(b/gcd)将解X锁定在区间(-b/gcd, b/gcd);
第四步: X = (X+b/gcd)%(b/gcd), 将解锁定在区间(0,b/gcd)中,此时为最小正整数解.
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define inf 0x3f3f3f3f3f
using namespace std;
typedef __int64 (ll);
void exgcd(ll a, ll b, ll &g, ll &x, ll &y){
if(b){
exgcd(b, a%b, g, y, x);
y = y-a/b*x;
} else {
x=1;
y=0;
g=a;
}
return ;
}
int main(){
ll a, b, c, k;
while(~scanf("%lld %lld %lld %lld", &a, &b, &c, &k), a||b||c||k){
ll A = c;
ll B = b-a;
ll n = (ll)1<<k;
ll x, y, g;
exgcd(A, n, g, x, y);//->ax+by=g;
if(B%g){
printf("FOREVER\n");
} else {
x = (x*(B/g))%n;// ->ax+by=c; (c = g*B/g)
x = (x%(n/g) + n/g)%(n/g);
printf("%I64d\n", x);
}
}
return 0;
}