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\n");

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\n",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;
}

 

你可能感兴趣的:(oop)