Description
for (variable = A; variable != B; variable += C) statement;
Input
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
题意:对于这个循环for (variable = A; variable != B; variable += C)。给出A,B,C和k(k表示变量是在k位机下的无符号整数),判断循环次数,不能终止输出"FOREVER".
思路:我们可以根据所给的循环和容易的得出公式a+c*x=b(mod 2^k),然而可以转换成 c*x=(b-a)mod(2^k)。令A=c,B=b-a,n=2^k,所以原式变成Ax=B (mod n)。
设线性模方程的一个解为x0
条件①:有d = gcd(a, n)
条件②:有d = ax1 + ny, 由扩展欧几里得(Egcd)得到x1的值
条件③:b % d == 0 (有解的条件)
则x0 = x1*(b/d);
证明:
因为:容易求得d = gcd (a, n), 则有d = ax1 + ny①(扩展欧几里得定理)
方程①2边同时模n得:d % n == ax1 % n②
又因为:b % d == 0, 即b是d的倍数;
所以(b/d)必为整数;
所以由②得: b % n == d*(b/d) % n == ax1*(b/d) % n == ax % n
所以很容易可以看出x = x1*(b/d)是方程的一个整数解,得证
需要注意的是: 把模线性方程求得的特解转化为正数之后,要模 b/gcd(a,b) ,而不是b
#include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <sstream> #include <algorithm> #include <set> #include <queue> #include <stack> #include <map> using namespace std; typedef long long LL; const int inf=0x3f3f3f3f; const double eps=1e-10; const double pi= acos(-1.0); LL exgcd(LL a,LL b,LL &x,LL &y) { if(b==0){ x=1; y=0; return a; } LL r=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-(a/b)*y; return r; } int main() { LL A,B,C,k,x,y; while(~scanf("%lld %lld %lld %lld",&A,&B,&C,&k)){ if(!A&&!B&&!C&&!k) break; LL a=C; LL b=(B-A); LL n=1ll<<k; LL d=exgcd(a,n,x,y); if(b%d) puts("FOREVER"); else{ x=x*(b/d)%n+n; printf("%lld\n",x%(n/d)); //对于无数个解形成的一群余数:周期个数是d,周期长度是n/d,也就是最小正整数解在n/d里 } } return 0; }
原文地址:http://blog.csdn.net/u013486414/article/details/46288919