大前提你要知道 拓展欧几里得的算法函数
首先 一定存在整数对满足方程 ax+by=gcd(a,b) 这里gcd(a,b)是最大公约数
同gcd一样我们可以用递归定义exgcd
假设已经求得 bx’+(a%b)y’=gcd(a,b)
已知a%b=a-(a/b)*b (为什么会这样 因为a/b取整)
带入得到
bx’+(a-(a/b)*b)y’=gcd(a,b)
ay’+b(x’-a(a/b)*y’)=gcd(a,b)
我们可以发现 令x’’=y’ y’’=x’-a(a/b)*y’
这就是递归过程的一部分
最后当b=0时有
a*1+b*0=a=gcd(a,b)
拓展欧几里得代码:
long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
long long d=a;
if(b!=0)
{
d=ex_gcd(b,a%b,y,x);
y=y-(a/b)*x;}
else
{
x=1;
y=0;
}
return d;
}
然后这题 首先已知方程 (A+Cx)mod(2^k)=B
那么就知道 存在一个数y使得 (2^k)*y+B=A+Cx 成立(这个很容易一眼看出来 自己举个例子就秒懂了)
变形就得到 Cx-(2^k)*y=B-A
就转换成了可以带入的方程式
最后通过通过拓展欧几里得求得d、x、y值,其中返回的x就是最小解x0,求d的原理是辗转相除法(欧几里德算法)
再利用MODULAR-LINEAR-EQUATION-SOLVER算法通过x0计算x值。注意x0可能为负,因此要先 + b/d 再模b/d。
看代码:
/*
qq:1239198605
ctgu_yyf
*/
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
long long d=a;
if(b!=0)
{
d=ex_gcd(b,a%b,y,x);
y=y-(a/b)*x;}
else
{
x=1;
y=0;
}
return d;
}
int main()
{
ios::sync_with_stdio(false);
long long aa,bb,cc,dd;
while(cin>>aa>>bb>>cc>>dd)
{
if(aa==0&&bb==0&&cc==0&&dd==0)
break;
//(aa+ccx)mod(2^dd)=bb;
//(2^dd)y+bb=aa+ccx
//ccx+(-(2^dd))y=bb-aa
long long a,b,c,x,y;
a=cc;
c=bb-aa;
b=(long long)1<<dd;
if(c==0)
{
cout<<"0"<<endl;
continue;
}
long long d=ex_gcd(a,b,x,y);
if(c%d)
{
cout<<"FOREVER"<<endl;
continue;
}
long long dm=b/d;
x=((x*c/d)%dm+dm)%dm;
cout<<x<<endl;
}
return 0;
}