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
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }