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

http://poj.org/problem?id=2115

题意:对于C的循环(for i = A; i != B; i+=C)问在k位存储系统内循环多少次结束;

   若循环有限次能结束输出次数,否则输出 FOREVER;

解:设x为循环次数;

   (A+C*x)%2^k = B;  

  则 C*x+A = 2^k*y+B; 

  所以 C*x - 2^k*y = B-A; 类似于a*x+b*y = c (或 a*x = c(mod b))模线性方程的形式,所以可以根据扩展欧几里得算法解决

  

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 long long exGcd(long long a,long long b,long long &x, long long &y)
 5 {
 6     if(b == 0)
 7     {
 8         x = 1;
 9         y = 0;
10         return a;
11     }
12     long long d = exGcd(b,a%b,x,y);
13     long long t = x;
14     x = y;
15     y = t-a/b*y;
16     return d;
17 }//a,b的最大公约数是d,且d = x*a+y*b表示;
18 
19 int main()
20 {
21     long long A,B,C,a,b,n;
22     int k;
23 
24     while(~scanf("%lld %lld %lld %d",&A,&B,&C,&k))
25     {
26         if(A == 0 && B == 0 && C == 0 && k == 0)
27             break;
28         a = C;
29         b = B-A;
30         n = 1LL<<k;//因为n是long long,所以2^k要写成lLL<<k;
31 
32         long long x,y,d;
33         d = exGcd(a,n,x,y);
34         if(b%d != 0)
35             printf("FOREVER
");
36         else
37         {
38             x = (x*(b/d))%n;//方程a*x = b(mod n)的最小解(其实我也不清楚怎么的得到的x0,先记着呗);
39             x = (x%(n/d)+n/d)%(n/d);//方程a*x = b(mod n)的最小整数解;
40             printf("%lld
",x);
41         }
42     }
43     return 0;
44 
45 }
View Code

 

推论1: 方程ax≡b(mod n)对于未知量x有解,当且仅当gcd(a,n) | b (b能被gcd(a,n)整除)。

即:若gcd(a,n)|b ==> 有一个解x,使得ax≡b(mod n).   

推论2:方程ax≡b(mod n)或者对模n有d个不同的解(有解当且仅当d | b),其中d=gcd(a,n),或者无解。   

定理1:设d=gcd(a,n),假定对整数x'和y'满足d=ax'+ny'(比如用扩展Euclid算法求出的一组解)。如果d | b,则该方程对模n有d个不同的解,方程ax≡b(mod n)有一个解x0满足x0=x'*(b/d) mod n 通解为xi = x0 + i*(n / d)(d = 0, 1, 2, ..., d - 1)。特别的设e=x0+n,方程ax≡b(mod n)的最小整数解x1=e mod (n/d),最大整数解x2=x1+(d-1)*(n/d)。

定理2:假设方程ax=b(mod n)有解,且x0是方程的任意一个解,则该方程对模n恰有d个不同的解(d=gcd(a,n)),分别为:xi=x0+i*(n/d) mod n 。

 

类似地: 可以求ax + by = c的整数解(x, y)。==> ax ≡ c(mod b), d = gcd(a, b) | c 时有解。有一个解x0 = x’* (c / d) mod b,  y0 = (-a * x0 - c) / b; 通解xi = x0 + i * (b / d), yi = y0 - i * (a / d) (i = 0, 1, 2, ..., d - 1)。

扩展欧几里得算法
int exgcd(int a, int b, int& x, int& y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int r = exgcd(b, a%b, x, y);
int t = x;
x = y;
y = t - a/b* y;
return r;
}

 

原文地址:https://www.cnblogs.com/LK1994/p/3365969.html