扩展欧几里得算法详见:@zhj5chengfeng
http://blog.csdn.net/zhjchengfeng5/article/details/7786595
对于二元一次不定方程: ax + by = c;
有解的充要条件是 : c % gcd(a,b) ==0;
可用扩展欧几里得算法求得 某一个解 x, 但不一定是最终解;
最终解应为X = x * c /gcd(a,b);
当然,此时 X 不一定是正数,可通过
X = ( X %(b/gcd(a,b)) + (b/gcd(a,b))) % (b/gcd(a,b));
来调整
应用例题:poj2115:
此题 容易推出 方程: (A + Cx)% 2^k = B;
即 Cx = (B-A) (mod 2^k) //(同余方程…)
再整理成 不定方程的形式就是: Cx + (2^k)y = (B-A)
然后 对应上面的解法 代入就 可以了。。。
代码
///poj2115
//Time; 16MS
//Memory: 724K
///编译器打三杠才清楚。。。请谅解
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long int LL;
LL ex_gcd(LL a, LL b, LL &x,LL &y)
{
if(b==0)
{
x = 1;
y = 0;
return a;
}
LL ans = ex_gcd(b,a%b,x,y);
LL temp = x;
x = y;
y = temp - a/b*y;
return ans;
}
int main()
{
LL A,B,C,k;
while(cin>>A>>B>>C>>k)
{
if(!A&&!B&&!C&&!k) break;
if(A==B) {cout<<"0"<<endl; continue;}
LL M = (LL)1<<k;
//cout<<M<<endl;
LL G = B-A;
///方程: C*x + M*y = G ;
LL x,y;
LL ans = ex_gcd(C,M,x,y);
///ans == gcd(C,M);
//cout<<ans<<endl;
//cout<<G<<endl;
if(G%ans != 0) {cout<<"FOREVER"<<endl; continue;}
///有解条件 G % gcd(C,M) == 0;
// cout<<x<<endl; //一个解
LL k = M/ans; //
LL ret = x*G/ans; ///最终解
ret = (ret%(k) + (k))%k; ///(调整)最终解,使之为可行的最小正整数
cout<<ret<<endl;
}
return 0;
}