题目大意:很好理解,一个for循环语句,从a开始到b结束,步长是c,模数是pow(2,k)
问,最少循环多少次,才能到达b,如果永远都到不了b,输出FOREVER
题解:其实就是求一个线性方程,cx=b( mod p)。问x最小是多少。
这个线性方程怎么来的呢?从a开始假设我们走了x步,到达了b,则a+cx=b( mod p)将a移到右边可得cx=(b-a)( mod p)。
这个线性方程怎么解呢? 假设cx在取了y次模得到了(b-a),那么cx-py=(b-a),也就是解这个二元一次方程。
很容易想到用EXGCD。然后就是关于x的最小值,计算出x后,只需要去一次模就可以了。
code:
//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0) {
x=1;y=0;
}
else {
exgcd(b,a%b,y,x);
y-=a/b*x;
}
}
int main(){
ll A,B,C,k;
while(cin>>A>>B>>C>>k){
if(A==0&&B==0&&C==0&&k==0) break;
ll p=(ll)1<<k;
ll b=B-A;
ll c=C;
if(c==0&&A!=B){
cout<<"FOREVER"<<endl;
continue ;
}
if(b%__gcd(c,p)==0){
ll d=__gcd(c,p);
b/=d;c/=d;p/=d;
ll x,y;
exgcd(c,p,x,y);x=x*b%p;
cout<<(x+p)%p<<endl;
}
else puts("FOREVER");
}
return 0;
}
对拓展欧里解决线性问题的总结:
1 类似于:ax+by=c.该方程有解的条件是 c%gcd(a,b)=0,然后a1=a/gcd(a,b),b1=b/gcd(a,b),c1=c/gcd(a,b),将方程转换成了a1x+b1y=c1。然后我们可以根据exgcd求出a1x+b1y=1时的x,然后只需要让x*=c1就是该方程的解,注意,这个解只是其中一个,该方程的通解为x=x+k*b,y=y-k*a。