题意简述:给你四个数字a,b,c,k.其实就是一个for循环for(i = a; i != b ; i = (I+c)%2^k);求循环经过几次结束,输出次数;如果循环不结束,则输出"FOREVER".
一开始想到的是暴搜....但是k <= 32,所以余数也就是<=2^32-1;暴搜会超时啊、、后来听说这是扩展GCD的题目,就朝着这个方向想了想,但是只怪自己会的太少,以前学的时候学的不扎实,又忘记了啊、、、最后还是鹏哥给我讲的,感觉讲的很详细,在这里谢谢鹏哥了啊、、、
扩展GCD是原理:ax+by = c;令d = gcd(a,b),原方程有整数解当且仅当d|c,bx+(a%b)y = 1 <=> ax+b(x-[a/b]*y) = 1;
解二元模线性方程 算法步骤:
整数a,b,c,设d = gcd(a,b) 再用欧几里得算法求gcd(a,b)的过程中求方程ax+by = d的一组整数解:
若 b = 0, 则x = 1, y = 0;
否则,递归调用gcd(b, a%b),可以得到bx`+(a%b)y` = d;的解x`, y`,令x = y`, y = x-[a/b]*y`既满足ax+by=d.若d|c,则有a(kx)+b(ky) = c;否则原方程无整数解。
这道题可以列出方程:(a + c*x) %2^k = b;所以 a + c*x = b + y*2^k <=>c*x-y*2^k = b-a;符合扩展gcd的公式所以可以求出d = exit_gcd(c,2^k),如果d是(b-a)的倍数则输出几倍、、、否则输出“FOREVER”、、注意输出的正负问题。。
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 15513 | Accepted: 3960 |
Description
for (variable = A; variable != B; variable += C) statement;
I.e., a loop which starts by setting variable to value A and while variable is not equal to B, repeats statement followed by increasing the variable by C. We want to know how many times does the statement get executed for particular values of A, B and C, assuming that all arithmetics is calculated in a k-bit unsigned integer type (with values 0 <= x < 2 k) modulo 2 k.
Input
The input is finished by a line containing four zeros.
Output
Sample Input
3 3 2 16 3 7 2 16 7 3 2 16 3 4 2 16 0 0 0 0
Sample Output
0 2 32766 FOREVER
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
long long x, y, f[40];
int exit_gcd(long long a, long long b)
{
if(b == 0)
{
y = 0;
x = 1;
return a;
}
long long p = exit_gcd(b, a%b);
long long temp = x;
x = y;
y = temp-(a/b)*y;
return p;
}
void ff()
{
int i;
f[0] = 1;
for(i = 1; i <= 33; i++)
f[i] = f[i-1]*2;
}
int main()
{
ff();
long long a, b, c, k, n, d;
while(cin >>a>>b>>c>>k)
{
if(!a && !b && !c && !k)
break;
n = f[k];
if(a > b)
b = ((b-a)%n+n)%n;
else
b = b-a;
d = exit_gcd(c,n);
if(b%d)
{
cout <<"FOREVER"<<endl;
continue;
}
n = n/d;
long long sum = (x*(b/d)%n+n)%n;
cout <<sum<<endl;
}
return 0;
}