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))模线性方程的形式,所以可以根据扩展欧几里得算法解决

  

 #include<stdio.h>
#include<string.h> long long exGcd(long long a,long long b,long long &x, long long &y)
{
if(b == )
{
x = ;
y = ;
return a;
}
long long d = exGcd(b,a%b,x,y);
long long t = x;
x = y;
y = t-a/b*y;
return d;
}//a,b的最大公约数是d,且d = x*a+y*b表示; int main()
{
long long A,B,C,a,b,n;
int k; while(~scanf("%lld %lld %lld %d",&A,&B,&C,&k))
{
if(A == && B == && C == && k == )
break;
a = C;
b = B-A;
n = 1LL<<k;//因为n是long long,所以2^k要写成lLL<<k; long long x,y,d;
d = exGcd(a,n,x,y);
if(b%d != )
printf("FOREVER\n");
else
{
x = (x*(b/d))%n;//方程a*x = b(mod n)的最小解(其实我也不清楚怎么的得到的x0,先记着呗);
x = (x%(n/d)+n/d)%(n/d);//方程a*x = b(mod n)的最小整数解;
printf("%lld\n",x);
}
}
return ; }

 

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

上一篇:POJ 1061 青蛙的约会(拓展欧几里得求同余方程,解ax+by=c)


下一篇:android 音频采集1