POJ2115:利用拓展欧几里德算法求解模线性方程
我可不可以理解为中国剩余定理中n=1的情况呢?
对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次才会结束
若在有限次内结束,则输出循环次数
否则输出死循环
设对于某组数据要循环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)
看到这里,如果b=1,这个方程的解就被称为乘法逆元,也就是之前博文中介绍的那个
该方程有解的充要条件为 gcd(a,n) | b ,即 b% gcd(a,n)==0
(乘法逆元中b=1,这是gcd(a,n)必须是1才可以,也就是a和n必须互质,这里是一般情况)
令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
一般我们都是求最小整数解,不是求通解,具体的形式在程序中体现
1 #include<cstdio> 2 // ax=b (mod n) 3 long long exgcd(long long a,long long b,long long &x,long long &y) 4 { 5 //扩展欧几里得算法 6 //返回a,b的最大公约数,ax+by=gcd(a,b),x,y为方程的一组解 7 if(b==0){x=1;y=0;return a;} 8 long long d=exgcd(b,a%b,x,y); 9 long long t=x;x=y;y=t-a/b*y; 10 return d; 11 } 12 long long solve(long long a,long long b,long long n) 13 { 14 long long x,y,x0; 15 long long d=exgcd(a,n,x,y); 16 if(b%d) return -1; 17 x0=(x*(b/d))%n; //特解 18 //for(int i=1;i<d;i++) 19 //printf("%lld",x0+i*(n/d)%n); 20 //对于不定方程,显然x0+k*b/d,y0-k*a/d,k∈Z就是所有解 21 long long ans=x0,s=n/d; 22 ans=(ans%s+s)%s; //最小整数解 23 return ans; 24 } 25 int main() 26 { 27 long long A,B,C,k; 28 while(scanf("%lld%lld%lld%lld",&A,&B,&C,&k)==4&&(A||B||C||k)) 29 { 30 long long a=C; 31 long long b=B-A; 32 long long n=1LL<<k; 33 long long ans=solve(a,b,n); 34 if(ans==-1) printf("FOREVER "); 35 else printf("%lld ",ans); 36 } 37 return 0; 38 }