知识点:

1、同余基本定义和定理、性质(剩余类、费马小定理、欧拉定理、欧拉函数、扩展欧拉定理)

2、扩展欧几里算法:求不定方程、同余方程、乘法逆元、中国剩余定理、扩展中国剩余定理

3、线性同余方程:利用扩展欧几里得算法

4、乘法逆元:若b、p互质,并且b|a,则存在一个整数使得,a/b=a*x(mod p),则称x为b的模p的逆元:可以用来解除法算式

5、中国剩余定理、扩展中国剩余定理(用的扩展欧几里得合并)

6、BSGS算法、扩展BSGS算法

 

1631:【例 1】青蛙的约会------>扩展欧几里得算法

(x+mt)=(y+nt) mod l
(x+mt)-(y+nt)=kl (x-y)+(m-n)t=kl 转化为 (m-n)t+kl=y-x t和k未知
如果gcd(m-n,l)能够整除y-x那么就有解

下面的代码常用:

之后要用扩展欧几里得算法求出x0,但是要带回去再乘以c/gcd ,再加上b/gcd保证非负数

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
LL x,y,m,n,l;
//(x+mt)=(y+nt) mod l
//(x+mt)-(y+nt)=kl  (x-y)+(m-n)t=kl  转化为  (m-n)t+kl=y-x t和k未知
//如果gcd(m-n,l)能够整除y-x那么就有解
LL gcd(LL a,LL b){
    if(b==0) return a;
    else return gcd(b,a%b);
}
void extend_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1;y=0;return;
    }
    extend_gcd(b,a%b,x,y);
    int temp=x;
    x=y;
    y=temp-(a/b)*y;
}
int main(){
    /*
    x+T*m = y+T*n  (%L)
  -->x-y = T*(n-m)+k*L
  -->T*(n-m)+k*L = x-y 类似(ax+by=c的形式)
  如果(x-y)%gcd(n-m,L)!=0无解
    */
    cin>>x>>y>>m>>n>>l;
    LL a=n-m;
    LL b=l;
    LL c=x-y;
    LL r=gcd(a,b);
    if(a<0){
        a=-a;
        c=-c;
    }
    if(c%r){
        printf("Impossible");
        return 0;
    } 
    //之后要用通解公式 x=x1+b/r*t , y=y1-a/r*t 
    LL xx=0,yy=0;
    extend_gcd(a,b,xx,yy);
    xx=xx*c/r;  //x0*c/gcd
    LL temp=b/r;  //b/gcd
    xx=(xx>=0)? (xx%temp):(xx%temp+temp);
    printf("%lld\n",xx);
return 0;
}
View Code

1632:【 例 2】[NOIP2012]同余方程

求关于 ax=1(modb)的最小正整数解。

 模板:对于没有限制的数,就用通用方法扩展欧几里得算法求,相当于转为方程ax+by=1,再取模把范围移动到0~b之间(非负)

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//这个就是模板了吧
LL a,b;
//求 ax=1(mod b) 的最小正整数解
//ax-1=by---ax+by=1  gcd(a,b)=1 互素
void extend_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1;y=0;return;
    }
    extend_gcd(b,a%b,x,y);
    LL tmp=x;
    x=y;
    y=tmp-(a/b)*y;
} 
LL gcd(LL a,LL b){
    if(b==0) return a;
    else return gcd(b,a%b);
}
int main(){
    cin>>a>>b;
    LL r=gcd(a,b);
    LL temp=b/r;
    LL  xx=0,yy=0;
    extend_gcd(a,b,xx,yy);
    //因为是1,所以不用xx*c/gcd 
    xx=(xx%temp+temp)%temp;
    cout<<xx<<endl;
return 0;
}
View Code

1633:【例 3】Sumdiv------>乘法逆元

若整数b、p互质,并且d|a,则存在一个整数x,使得a/b=ax(mod p),x称为bmodp的一个逆

若p是质数,可以用费马小定理,b^(p-1)=1(mod p)得到 b*(b^(p-2))=1(mod p),得到b^(p-2)就是b模p的逆

如果只是保证互质,那么就求解同余方程   bx=1(mod p) 

 求出A的约数之和,然后需要全部都乘以B

因为一个数A^B能够表示成多个质数的幂相乘的形式,即A^B=a1^n1*a2^n2*....*am^nm。
所以的所有约数之和sum=(1+a1,+a1^2 +..+a1^n1)*(1+a2+a2^2+...+a2^n2)*(1+a3+a3^2+...+a3^n3)*....*(1+am+am^2+...+am^nm)mod 9901。
对于每一个(1+ai,+ai^2 +..+ai^ni)mod 9901=(ai^(ni+1)/(ai-1))mod9901,可以先用快速幂计算分子ai^(ni+1)。
因为9901是质数,只要ai-1不是9901的倍数,就只需要计算ai-1的乘法逆元inv,用乘inv代替除以ai-1,直接计算出等比数列求和公式的结果。
特别地,若ai-1是9901的倍数,此时乘法逆元不存在,但是aimod9901=1,所以1+ai+ai^2+...+ai^ni=(1+1+1+...+1)=(ni+1)
如果ai-1不是9901的倍数,那么可以直接用费马小定理 a/b=a*x(mod p) 如果p为质数,且b<p,那么inv(b)=b^(p-2)

注意在处理数的时候,要在合适的位置把b也要考虑进去啊。。。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int mod=9901;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
/*
因为一个数A^B能够表示成多个质数的幂相乘的形式,即A^B=a1^n1*a2^n2*....*am^nm。
所以的所有约数之和sum=(1+a1,+a1^2 +..+a1^n1)*(1+a2+a2^2+...+a2^n2)*(1+a3+a3^2+...+a3^n3)*....*(1+am+am^2+...+am^nm)mod 9901。
对于每一个(1+ai,+ai^2 +..+ai^ni)mod 9901=(ai^(ni+1)/(ai-1))mod9901,可以先用快速幂计算分子ai^(ni+1)。
因为9901是质数,只要ai-1不是9901的倍数,就只需要计算ai-1的乘法逆元inv,用乘inv代替除以ai-1,直接计算出等比数列求和公式的结果。
特别地,若ai-1是9901的倍数,此时乘法逆元不存在,但是aimod9901=1,所以1+ai+ai^2+...+ai^ni=(1+1+1+...+1)=(ni+1)
如果ai-1不是9901的倍数,那么可以直接用费马小定理   a/b=a*x(mod p) 如果p为质数,且b<p,那么inv(b)=b^(p-2) 
*/
int p[20],c[20],a,b,m,ans=1;
void divide(int n){
	m=0;
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			p[++m]=i;
			c[m]=0;
		}
		while(n%i==0){
			c[m]++;
			n/=i;
		}
	}
	if(n>1){
		p[++m]=n;c[m]=1;
	}
}
int power(int a,LL b){
	int c=1;
	for(;b;b>>=1){
		if(b&1) c=(LL)c*a%mod;
		a=(LL)a*a%mod;
	}
	return c;
}
int main(){
 	cin>>a>>b;
	divide(a);
	for(int i=1;i<=m;i++){
		if((p[i]-1)%mod==0){
			//没有逆元的时候,特判
			ans=((LL)b*c[i]+1)%mod*ans%mod;
			continue;
		}
		int x=power(p[i],(LL)b*c[i]+1); //分子。用快速幂
		x=(x-1+mod)%mod;
		int y=p[i]-1; //分母
		y=power(y,mod-2); //根据费马小定理求出分子逆元 
		ans=(LL)ans*x%mod*y%mod;
	}   
	cout<<ans<<endl;
return 0;
}

  

1634:【例 4】曹冲养猪------>中国剩余定理

  中国剩余定理(孙子定理)

https://www.cnblogs.com/wkfvawl/p/9633188.html

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
LL n;
//中国剩余定理(孙子定理)
//https://www.cnblogs.com/wkfvawl/p/9633188.html 
LL aa[12],bb[12];
void extend_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1;
        y=0;return;
    }
    extend_gcd(b,a%b,x,y);
    LL tmp=x;
    x=y;
    y=tmp-(a/b)*y;
} 
LL gcd(LL x,LL y){
    if(y==0) return x;
    else return gcd(y,x%y);
}

int main(){
    scanf("%lld",&n);
    
    LL mod=1;
    for(int i=1;i<=n;i++){
        scanf("%lld %lld",&aa[i],&bb[i]);
        mod*=aa[i];
    } 
    LL ans=0;
    LL x,y;
    for(int i=1;i<=n;i++){
        LL p=mod/aa[i];
        extend_gcd(p,aa[i],x,y);
        //cout<<x<<endl;
        ans=(ans+bb[i]*x*p)%mod;
    }
    cout<<(ans+mod)%mod;
    /*   超时到怀疑人生哈哈哈哈 
    for(LL i=mm;;i++){
        bool flag=0;
        for(int j=1;j<=n;j++){
            if(!judge(i-bb[j],aa[j])) {
                flag=1;break;
            }
        }
        if(!flag){
            cout<<i<<endl;break;
        }
    }
    */
return 0;
}
View Code

1635:【例 5】Strange Way to Express Integers------>用扩展欧几里得算法求出同余方程组

变形是需要判断有没有解
//中国剩余定理的要求就是:m1,m2....mn两两互素
//但是如果不是两两互素的话,那么就需要扩展中国剩余定理
//https://www.cnblogs.com/zwfymqz/p/8425731.html

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1e5+10;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//变形是需要判断有没有解
//中国剩余定理的要求就是:m1,m2....mn两两互素
//但是如果不是两两互素的话,那么就需要扩展中国剩余定理
//https://www.cnblogs.com/zwfymqz/p/8425731.html 
LL n;
//x=c1(mod m1)
LL c[maxn],m[maxn],x,y;
LL gcd(LL a,LL b){
    if(b==0) return a;
    return gcd(b,a%b);
}
LL extend_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1;y=0;return a;
    }
    LL r=extend_gcd(b,a%b,x,y);
    LL tmp=x;
    x=y;
    y=tmp-(a/b)*y;
    return r;
}
LL inv(LL a,LL b){  //a在模b下的逆
    LL r=extend_gcd(a,b,x,y); 
    while(x<0) x+=b; //取最小非负的逆 
    return x;
} 
int main(){
    while(~scanf("%lld",&n)){
        for(int i=1;i<=n;i++){
            scanf("%lld %lld",&m[i],&c[i]);
        }
        bool flag=0;
        for(int i=2;i<=n;i++){  //两两合并位1个,并继续扩展 
            LL m1=m[i-1],m2=m[i];
            LL c1=c[i-1],c2=c[i];
            LL t=gcd(m1,m2);
            if((c2-c1)%t!=0){
                flag=1;break;  //必须余数为0 因为式子中要出现相除 
            }
            m[i]=(m1*m2)/t;
            c[i]=(inv(m1/t,m2/t)*(c2-c1)/t)%(m2/t)*m1+c1;
            c[i]=(c[i]%m[i]+m[i])%m[i];
        }
        printf("%lld\n",flag? -1:c[n]);
    }
return 0;
}
View Code

1636:【例 6】计算器------>高次同余方程BSGS算法

 三种计算

第一种,就是快速幂

第二种,就是同余公式的运用

第三种,高次同余方程

BSGS可以解决高次同余方程:
//https://www.cnblogs.com/kamimxr/p/11555986.html

用map存储,具体百度

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//1.y^zmod p
//2. x*y=z(mod p)
//3. y^x=z(mod p)

LL   js1(LL y,LL z,LL p){
    LL tmp=1;
    while(z){
        if(z&1) tmp=tmp*y%p;
        y=y*y%p;
        z>>=1;
    }
    return tmp%p;
}
void extend_gcd(LL a,LL b,LL &x,LL &y){
        if(b==0){
        x=1;
        y=0;return;
    }
    extend_gcd(b,a%b,x,y);
    LL tmp=x;
    x=y;
    y=tmp-(a/b)*y;
}
LL gcd(LL a,LL b){
    if(b==0 ) return a;
    else return gcd(b,a%b);
}
//x*y=z(mod p)  ax=b(mod m)
//ax+my=b
//y*x+p*k=z  已知y,p,z 
//求出x0之后
//最小非负解:((x=x0*z/gcd)+p/gcd)%(p/gcd)
void js2(LL y,LL z,LL p){
    LL A=y,B=z,M=p;
    LL xx,yy;
    extend_gcd(A,M,xx,yy);
    //gcd(a,m)%b==0
    LL d=gcd(y,p);
    if(z%d){
        printf("Orz, I cannot find x!\n");return;
    }
    xx=((xx*z/d)%(p/d)+p/d)%(p/d);
    printf("%lld\n",xx);
    //return (xx%M+M)%M;
}
//y^x=z(mod p)
//BSGS可以解决高次同余方程:
//https://www.cnblogs.com/kamimxr/p/11555986.html

void js3(LL a,LL ans,LL p){
    map<LL,LL> myhash;
    ans%=p;
    int tmp=sqrt(p)+1;
    for(int i=0;i<tmp;i++){
        //js1其实就是快速幂 
        myhash[(ans)*js1(a,i,p)%p]=i;
    }
    a=js1(a,tmp,p)%p;
    if(a==0&&ans==0){
        printf("1\n");return;
    }
    if(a==0&&ans!=0){
        printf("Orz, I cannot find x!\n");
        return;
    }
    for(int i=0;i<=tmp;i++){
        if(myhash.find(js1(a,i,p))!=myhash.end()&&(i*tmp-myhash[js1(a,i,p)]>=0)){
            printf("%d\n",i*tmp-myhash[js1(a,i,p)]);
            return;
        }
    }
    printf("Orz, I cannot find x!\n");
} 
int main(){
    int t,k;
    LL y,z,p;
    while(~scanf("%d %d",&t,&k)){
        if(k==1){
            for(int i=1;i<=t;i++){
                scanf("%lld %lld %lld",&y,&z,&p);
                printf("%lld\n",js1(y,z,p));
            }
        }
        else if(k==2){
            for(int i=1;i<=t;i++){
                scanf("%lld %lld %lld",&y,&z,&p);
                js2(y,z,p);
            }
        }
        else if(k==3){
            ////y^x=z(mod p)
            for(int i=1;i<=t;i++){
                scanf("%lld %lld %lld",&y,&z,&p);
                js3(y,z,p);
            }
        }
    }
return 0;
}
View Code

 

1637:荒岛野人

//和前面两道中国剩余定理不同的是,这个是每一年的余数都不能相同
//其实我一开始想的也是暴力,但是换一种暴力的思路
//要使得每一年还活着的野人居住的地方都不一样,就可以转化为思考住在一起的方程没有解或者解不符合条件
/*
以有野人的居住的山洞的最大编号作为初始的山洞数,从这里开始搜索:如果此时的山洞数符合条件就直接输出,否则山洞数加一。至于判断的过程,就是很暴力的枚举任意两个野人。
我们假设经过若干年后有两个野人处在了同一个山洞中,设i,j为野人编号,m为此时判断的山洞数,x为经过了多少年。那么就很容易得到
c[i]+x*p[i]≡c[j]+x*p[j](mod m)
稍稍变形得
(p[i]-p[j])*x≡c[j]-c[i](mod m)
那这不就是一个简单的线性同余方程嘛!
接下来就好办多了,用拓展欧几里得算法解出x,若无解(即c[j]-c[i]不是gcd(p[i]-p[j],m)的整数倍),那就说明这个山洞数满足“没有任何两个野人处在同一个山洞中”的条件,继续枚举其
他野人;若有解,那还要再分两种情况:
解得的x>min(l[i],l[j]),即此时两个野人至少已经die了一个了,那么活野人和死野人处不处在同一个山洞已经无所谓了,不碍事,继续枚举!
解得的x<=min(l[i],l[j]),那没办法,两个野人都活着,却还处在同一个山洞里,说明这个山洞数不符题意,直接返回false。
然鹅这道题还不能就这样轻易的AC掉,注意:由于p[i]-p[j]有可能为负,所以gcd(p[i]-p[j],m)也有可能为负,那么在拓展欧几里得算法中求解x时,一定要注意将m/(gcd(m,p[i]-p[j]))
带上abs()!
https://blog.csdn.net/anglanjing7414/article/details/101189720

!还是要注意细节:要考虑如果有解的情况下,求出来的值x有没有超过寿命,还有负数问题

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//和前面两道中国剩余定理不同的是,这个是每一年的余数都不能相同
//其实我一开始想的也是暴力,但是换一种暴力的思路
//要使得每一年还活着的野人居住的地方都不一样,就可以转化为思考住在一起的方程没有解或者解不符合条件

int n;
int c[20],p[20],l[20];
//初始位置、移动、寿命
int gcd(int x,int y){
	if(y==0) return x;
	else return gcd(y,x%y);
}
void exgcd(int a,int b,int &d,int &x,int &y){ //顺带求出了最大公约数 
	if(b==0){
		x=1;y=0;d=a;return;
	}
	exgcd(b,a%b,d,x,y);
	int tmp=x;
	x=y;
	y=tmp-(a/b)*y;
	return;
}
bool judge(int m){
	//(p[i]-p[j])*x≡c[j]-c[i](mod m)
	int a,b,cc,x,y,d;
	for(int i=1;i<=n-1;i++){
		for(int j=i+1;j<=n;j++){
			 a=p[i]-p[j];
			 b=m;
			 cc=c[j]-c[i];
			 if(cc%gcd(a,b)!=0) continue; //无解
			 exgcd(a,b,d,x,y);  //d=gcd(a,b)
			 int t=abs(b/d);
			 //要保证t是正数 
			 x=((x*cc/d)%t+t)%t;
			 if(x<=min(l[i],l[j])) return false;
		}
	}
	return true;
}
int main(){
	int maxx=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d %d %d",&c[i],&p[i],&l[i]);
		maxx=max(maxx,c[i]);
	}
	for(int i=maxx;;i++){
		if(judge(i)){
			printf("%d\n",i);
			break;
		}
	}
return 0;
}

  

1638:五指山

模板题

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
int t;
LL n,d,x,y;
//(dt+x)%n=y   dt+mn=y-x
//a=d  b=n c=y-x
LL gcd(LL x,LL y){
	if(y==0) return x;
	else return gcd(y,x%y);
}
void exgcd(LL a,LL b,LL &xx,LL &yy){
	if(b==0){
		xx=1;yy=0;return;
	}
	exgcd(b,a%b,xx,yy);
	LL tmp=xx;
	xx=yy;
	yy=tmp-(a/b)*yy;
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%lld %lld %lld %lld",&n,&d,&x,&y);
		//x%=n;
		//y%=n;
		LL a=d,b=n,c=y-x;
		LL r=gcd(a,b);
		LL tmp=b/r;
		if(c%r){
			printf("Impossible\n");continue;
		}
		LL xx,yy;
		exgcd(a,b,xx=0,yy=0);
		
		xx=(xx*c)/r;
		xx=(xx%tmp+tmp)%tmp;
		printf("%lld\n",xx);
	}
	
return 0;
}

  

1639:Biorhythms

 

 

其实就是中国剩余定理的应用,求通解 

这道题有些细节:特列输出,还有如果结果还小于d,那么累加的是23*28*33 

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//这个应该就是中国剩余定理了吧
//但是结果计算,通解? 
int mm[4]={23,28,33};
int aa[4];
int p,e,i,d;
int op=0;
void exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;y=0;return;
	}
	exgcd(b,a%b,x,y);
	int tmp=x;
	x=y;
	y=tmp-(a/b)*y;
}
void crt(){
	int m=1,ans=0,t,x,y;
	m=23*28*33;
	
	for(int i=0;i<3;i++){
		t=m/mm[i];
		exgcd(t,mm[i],x=0,y=0);
		ans=(ans+aa[i]*x*t)%m;
	}
	while(ans<=d){   //如果这样的结果还小于d,那么累加的是23*28*33 
		ans+=m;
	}
	ans=ans-d;
	printf("Case %d: the next triple peak occurs in %d days.\n",++op,ans);
}
int main(){
	while(~scanf("%d %d %d %d",&aa[0],&aa[1],&aa[2],&d)){
		if(aa[0]==-1&&aa[1]==-1&&aa[2]==-1&&d==-1) break;
		if(aa[0]==0&&aa[1]==0&&aa[2]==0&&d==0){
			printf("Case %d: the next triple peak occurs in 21252 days.\n",++op);   //特列 
			continue; 
		}
		crt();
	}
return 0;
}

  

1640:C Looooops

 

 要理解这个k位存储系统的意思!!!!---->mod=2^k  这个意思

所以分析最重要,分析出来其实就是模板题

(A+k*C)%MOD=B;
A+C*p1 = B (%Mod) Mod=2^k
C*p1+Mod*p2 = B-A (类ax+by=c的形式)
求p1

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
typedef long long LL;
typedef unsigned long long ull;
//模板题
//(A+k*C)%MOD=B;
/*
A+C*p1 = B (%Mod) Mod=2^k
C*p1+Mod*p2 = B-A (类ax+by=c的形式)
求p1
*/ 
LL A,B,C,k;
LL gcd(LL x,LL y){
	if(y==0) return x;
	else return gcd(y,x%y);
}
void exgcd(LL a,LL b,LL &x,LL &y){
	if(b==0){
		x=1;y=0;return;
	}
	exgcd(b,a%b,x,y);
	LL tmp=x;
	x=y;
	y=tmp-(a/b)*y;
	return;
}
int main(){
	while(~scanf("%lld %lld %lld %lld",&A,&B,&C,&k)){
		if(A==0&&B==0&&C==0&&k==0) break;
		LL mod=1LL<<k;
		LL a,b,c,r,x,y,tmp;
		a=C;b=mod;c=B-A;
		r=gcd(a,b);
		tmp=b/r;
		if(c%r){
			printf("FOREVER\n");
			continue;
		}
		exgcd(a,b,x=0,y=0);
		x=x*c/r;
		x=(x>=0)? (x%tmp):(x%tmp+tmp);
		printf("%lld\n",x);
	}
return 0;
}

  

 

 posted on 2020-05-30 15:28  shirlybabyyy  阅读(328)  评论(0编辑  收藏  举报