扩展中国剩余定理(模数不互质)
洛谷P4777 【模板】扩展中国剩余定理(EXCRT)
#include<bits/stdc++.h> using namespace std; #define ll long long #define N 100005 ll r[N],p[N]; ll a1,a2,n1,n2; int nn; 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,y,x); y-=a/b*x; return d; } ll mul(ll a,ll x,ll mod) { ll ans=0,m=0; if(x<0) m=1,x=-x; while(x) { if(x&1) ans=(a+ans)%mod; x=x>>1; a=(a+a)%mod; } if(m) return -ans; return ans; } int main() { scanf("%d",&nn); scanf("%lld%lld",&p[1],&r[1]); //r1是前i-1个方程的解 ll r1=r[1],lcm=p[1];//一边使用n次exgcd 一边求lcm for(int i=2;i<=nn;i++) { ll x,y; scanf("%lld%lld",&p[i],&r[i]);//输入顺序 ll c=(r[i]-r1);//式子右边 ll g=exgcd(lcm,p[i],x,y); x=mul(x,c/g,p[i]);//龟速乘 防止模数较大 一乘就爆long long r1+=x*lcm;//求出一个可行的x 更新前i个方程的解 lcm=lcm/g*p[i];//lcm是前i个p[i]的最小公倍数 所以要/g r1=(r1%lcm+lcm)%lcm;//防止为负数 保证r1是最小的解 } printf("%lld\n",r1); } /* 3 11 6 25 9 33 17 */
普通中国剩余定理:
洛谷P1495 曹冲养猪
#include<bits/stdc++.h> using namespace std; #define ll long long int n; ll m[15],M=1,a[15]; 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); ll z=x; x=y; y=z-(a/b)*y; return d; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lld%lld",&m[i],&a[i]);//有时候int*int会爆long long 所以一定记得开 M*=m[i]; } ll ans=0; for(int i=1;i<=n;i++){ ll aa=M/m[i],b=m[i],x,y; ll d=exgcd(aa,b,x,y); //求一个x使得:mi*x (=) 1 (%m[i]) //这样左右两边同时*a[i]时就满足第i个方程了 ans=(ans+M/m[i]*x*a[i] +M) %M;//防止加爆 } printf("%lld\n",(ans+M) %M); } /* 3 3 1 5 1 7 2 */