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