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 }
推论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;
}