题意:多组输入,每组给A,B,C,k(0<=A,B,C<2^k)。求出statement运行了多少次?
注意variable对2^k取余。
题解:转化为已有知识,=>,解最小的非负数x。
注意事项:
- 注意B=A的时候答案直接为0
- 如果a==0,b==0,exgcd那应该是没有解的,返回-1。好在这里不可能b=2^k=0。
- 这里c,2^k都为非负数,c=B-A如果小于0,那就先f=-1,然后解a*x+b*y=-c的最小的非负数解,然后后mod_x-x即为a*x+b*y=c的最小非负数解(这里要对exgcd算法有深入的理解)
- 其他都是比较常规的操作了
代码:
#include <cstdio>
#include <iostream>
#define int long long
#define read(x) scanf("%lld", &x)
#define print(a, c) printf("%lld%c", a, c)
#define dbg(x) cout << #x << "===" << x << endl;
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
int A, B, C, k;
int qpow(int a, int p) {
int res = 1;
while (p) {
if (p & 1) res *= a;
p >>= 1, a *= a;
}
return res;
}
int exgcd(int a, int b, int &x, int &y) {
if (a == 0 && b == 0) return -1; //不可能的情况吧
if (!b) {
x = 1, y = 0;
return a;
}
int g = exgcd(b, a % b, y, x);
y -= a / b * x;
return g;
}
signed main() {
while (scanf("%lld%lld%lld%lld", &A, &B, &C, &k) != EOF) {
if (A + B + C + k == 0) break;
int a = C, b = qpow(2, k), c = B - A; // a*x+b*(-y)=c。以下都不用考虑y
if (c == 0) {
puts("0");
continue;
}
int f = 1;
if (c < 0) c = -c, f = -1; //先解a*x+b*y=-c,然后再处理a*b+b*y=c
int X0, Y0;
int g = exgcd(a, b, X0, Y0);
if (c % g)
puts("FOREVER");
else {
int mod_x = b / g; //还是用a,b,c,x,y,X0,Y0,g这些我常用的符号好
int ans = (c / g * X0 % mod_x + mod_x) %
mod_x; // a*x+b*y=-c的x的最小正整数解
if (f == -1)
ans = mod_x - ans; // 转化得到a*x+b*y=c的x的最小正整数解
// cout << ">>>>>>>>>>>>>";
print(ans, '\n');
}
}
return 0;
}