POJ2115 C Looooops 模线性方程(扩展欧几里得)

题意:很明显,我就不说了

分析:令n=2^k,因为A,B,C<n,所以取模以后不会变化,所以就是求(A+x*C)%n=B

转化一下就是求 C*x=B-A(%n),最小的x

令a=C,b=B-A

原式等于ax=b(mod n) 这就是标准的解模线性方程

该方程有解的充要条件是d=gcd(n,a) && d|b(可以根据这一条判断是否FOREVER)

然后参考算法导论应用扩展欧几里得求解x

a*x0+n*y0=d

x=x0*(b/d)(mod n)

然后应用多解条件求最小正整数解,即解的最小间距t=n/d,x+=i*t,i=0,1,..d-1

x=(x%t+t)%t

代码:

#include <cstdio>
#include <iostream>
#include <ctime>
#include <vector>
#include <cmath>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
LL x,y;
LL Egcd(LL a,LL b)
{
    if(b==0)
    {
       x=1;
       y=0;
       return a;
    }
    int res=Egcd(b,a%b);
    LL tmp=x;
    x=y;
    y=tmp-a/b*y;
    return res;
}
int main()
{
    LL a,b,c,k;
    while(~scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&k))
    {
        if(!a&&!b&&!c&&!k)break;
        LL n=(1ll<<k);
        LL d=Egcd(c,n);
        if((b-a)%d)
        {
            printf("FOREVER\n");
            continue;
        }
        x*=((b-a)/d);
        x=(x%(n/d)+n/d)%(n/d);
        printf("%I64d\n",x);
    }
    return 0;
}
View Code

 

posted @ 2016-02-23 21:53  shuguangzw  阅读(138)  评论(0编辑  收藏  举报