exgcd&&中国剩余定理专题练习
hdu1573求中国剩余定理解的个数
#include <iostream> #include <cstdio> using namespace std; int a[100],b[100]; int exgcd(int a,int b,int &x,int &y){ if(b==0){ x=1;y=0;return a; } int d=exgcd(b,a%b,x,y),t; t=x;x=y;y=t-a/b*y; return d; } int main(){ int T;scanf("%d",&T); while(T--){ int n,m;scanf("%d%d",&n,&m); for(int i=0;i<m;++i) scanf("%d",a+i); for(int i=0;i<m;++i) scanf("%d",b+i); int a1=a[0],r1=b[0],flag=0; for(int i=1;i<m;++i){ int a2=a[i],r2=b[i]; int d=r2-r1,x,y,GCD=exgcd(a1,a2,x,y); if(d%GCD){ flag=1;break; } x*=d/GCD;int mod=a2/GCD; x=(x%mod+mod)%mod; r1=x*a1+r1; a1=a1*a2/GCD; } if(r1>n||flag) printf("0\n"); else printf("%d\n",(n-r1)/a1+1-(r1==0?1:0));//没考虑r1==0的情况 } }
poj1061 列同余方程,exgcd解方程
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1;y=0;return a; } ll d=exgcd(b,a%b,x,y),t; t=x;x=y;y=t-a/b*y; return d; } int main(){ ll x,y,m,n,L; while(~scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&L)){ ll rx,ry,GCD,D=((y-x)%L+L)%L,A=((m-n)%L+L)%L; GCD=exgcd(A,L,rx,ry); if(D%GCD) { printf("Impossible\n");continue; } ll mod=L/GCD;rx*=D/GCD; rx=(rx%mod+mod)%mod; printf("%I64d\n",rx); } return 0; }
poj2115 不互质情况下又需要求类似逆元的东西
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; ll A,B,C,k; ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0) { x=1;y=0;return a; } ll d=exgcd(b,a%b,x,y),t; t=x;x=y;y=t-a/b*y; return d; } int main(){ while(~scanf("%I64d%I64d%I64d%I64d",&A,&B,&C,&k)){ if(A+B+C+k==0) break; ll n=(1ll<<(k)); ll D=((B-A)%n+n)%n,x,y,GCD; GCD=exgcd(C,n,x,y); if(D%GCD){ printf("FOREVER\n");continue; } ll mod=n/GCD;x*=D/GCD; x=(x%mod+mod)%mod; printf("%I64d\n",x); } return 0; }
poj2891 一元线性方程组-不互质的中国剩余定理
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1;y=0;return a; } ll d=exgcd(b,a%b,x,y),t; t=x;x=y;y=t-a/b*y; return d; } int main(){ ll k; while(~scanf("%I64d",&k)){ ll a1,r1,a2,r2,ans;scanf("%I64d%I64d",&a1,&r1); int flag=0; for(int i=1;i<k;++i){ scanf("%I64d%I64d",&a2,&r2); if(flag) continue; ll d=r2-r1,x,y,GCD=gcd(a1,a2); if(d%GCD) { flag=1;continue; } ll A1=a1/GCD,A2=a2/GCD,D=d/GCD; exgcd(A1,A2,x,y); x*=D;x=(x%A2+A2)%A2; r1=x*a1+r1; a1=a1*a2/GCD; } if(flag) printf("-1\n"); else printf("%I64d\n",r1); } return 0; }
poj 1006 高峰期出现的同一天,中国剩余定理
#include <iostream> #include <cstdio> using namespace std; int p,e,i,d; int exgcd(int a,int b,int &x,int &y){ if(b==0){ x=1;y=0;return a; } int d=exgcd(b,a%b,x,y),t; t=x;x=y;y=t-a/b*y; return d; } int main(){ int cas=0; while(~scanf("%d%d%d%d",&p,&e,&i,&d)){ if(p+e+i+d==-4) break; int N=23*28*33,K,x,y,ans=0; exgcd(23,K=N/23,x,y);y=(y%23+23)%23; ans=(ans+K*y*(p-d))%N; exgcd(28,K=N/28,x,y);y=(y%28+28)%28; ans=(ans+K*y*(e-d))%N; exgcd(33,K=N/33,x,y);y=(y%33+33)%33; ans=(ans+K*y*(i-d))%N; if(ans<=0) ans+=N; printf("Case %d: the next triple peak occurs in %d days.\n",++cas,ans); } return 0; }
poj2142 对exgcd得出的|s|+|t|最小的解,求s>0时t为多少,t>0时s为多少,两个方向求一下最小正整数解
#include <iostream> #include <cstdio> using namespace std; int a,b,d; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } int exgcd(int a,int b,int &x,int &y){ if(b==0){x=1;y=0;return a;} int d=exgcd(b,a%b,x,y),t; t=x;x=y;y=t-a/b*y; return d; } int main(){ while(~scanf("%d%d%d",&a,&b,&d)){ if(a+b+d==0) break; int GCD=gcd(a,b); a/=GCD,b/=GCD,d/=GCD; int x,y;exgcd(a,b,x,y); int x1,y1,x2,y2; x1=x*d; x1=(x1%b+b)%b;y1=(d-a*x1)/b;if(y1<0) y1=-y1; y2=y*d; y2=(y2%a+a)%a;x2=(d-b*y2)/a;if(x2<0) x2=-x2; if(x1+y1>x2+y2) { x1=x2;y1=y2; } printf("%d %d\n",x1,y1); } return 0; }