模线性方程 poj2115
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 long long exgcd(long long a,long long b,long long &x,long long &y) 7 { 8 if(b==0) 9 { 10 x=1; 11 y=0; 12 return a; 13 } 14 long long ret=exgcd(b,a%b,x,y); 15 long long tmp=x; 16 x=y; 17 y=tmp-a/b*y; 18 return ret; 19 } 20 21 int main() 22 { 23 long long a,b,c,k,x,y; 24 while(scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&k)!=EOF) 25 { 26 if(a==0&&b==0&&c==0&&k==0) 27 break; 28 long long n=(long long)1<<k; 29 long long e=exgcd(c,n,x,y); 30 if((b-a)%e) 31 cout<<"FOREVER"<<endl; 32 else 33 { 34 long long t=n/e; 35 x = (x * (b - a) / e % t + t) % t; 36 cout<<x<<endl; 37 } 38 } 39 return 0; 40 }
题意不难理解,只是利用了 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的值。
下面将结合《算法导论》第2版进行简述,因此先把上面的方程变形,统一符号。
令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