【题意】对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次才会结束。若在有限次内结束,则输出循环次数。否则输出FOREVER。

【解题思路】

           题意不难理解,只是利用了 k位存储系统 的数据特性进行循环。例如int型是16位的,那么int能保存2^16个数据,即最大数为65535(本题默认为无符号),当循环使得i超过65535时,则i会返回0重新开始计数,如i=65534,当i+=3时,i=1,其实就是 i=(65534+3)%(2^16)=1。有了这些思想,设对于某组数据要循环x次结束,那么本题就很容易得到方程: x=[(B-A+2^k)%2^k] /C,即 Cx=(B-A)(mod 2^k)  此方程为 模线性方程,本题就是求X的值。

     下面将结合红书进行简述,因此先把上面的方程变形,统一符号。令a=C  ,b=B-A ,n=2^k,那么原模线性方程变形为:ax=b (mod n),该方程有解的充要条件为 gcd(a,n) | b ,即 b% gcd(a,n)==0,令d=gcd(a,n),有该方程的 最小整数解为 x = e (mod n/d),其中e = [x0 mod(n/d) + n/d] mod (n/d) ,x0为方程的最小解,那么原题就是要计算b% gcd(a,n)是否为0,若为0则计算最小整数解,否则输出FOREVER。剩下的就是套单变元模线性方程的板子了。

【AC代码】

           

#include <stdio.h>

typedef long long LL;
LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }else{
        LL r = ex_gcd(b,a%b,y,x);
        y-=x*(a/b);
        return r;
    }
}

int main()
{
    int A,B,C,k;
    while(scanf("%d%d%d%d",&A,&B,&C,&k)!=EOF)
    {
        if(A==0&&B==0&&C==0&&k==0)return 0;
        LL a = (LL)C;
        LL b = (LL)(B-A);
        LL n = 1LL<<k;
        LL x,y;
        int d = ex_gcd(a,n,x,y);
        if(b%d!=0)
        {
            puts("FOREVER");
        }
        else
        {
            x = (x*(b/d))%n; //ax = b(mod n)最小解
            x = ((x%(n/d)+n/d))%(n/d);//ax = b(mod n)最小整数解
            printf("%I64d\n",x);
        }
    }
    return 0;
}

【补充】单变元模线性方程板子

[说明]d = ex_gcd(a,n),先使用ex_gcd()求ax+ny=d的解,如果b不能整除d则无解,否则mod n意义下得解有d个,可以通过对某个解不断的加n/d得到。

typedef long long LL;
vector<LL>line_mod_equation(LL a,LL b,LL n)
{
    LL x,y;
    LL d = ex_gcd(a,n,x,y);
    vector<LL>ans;
    ans.clear();
    if(b%d!=0)
    {
        x%=n,x+=n,x%=n;
        ans.push_back(x*(b/d)%(n/d));
        for(LL i=1; i<d; i++)ans.push_back((ans[0]+i*n/d)%n);
    }
    return ans;
}