中国剩余定理(普通+扩展)

扩展中国剩余定理(模数不互质)

洛谷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
",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
",(ans+M) %M);
}
/*
3
3 1
5 1
7 2
*/
原文地址:https://www.cnblogs.com/mowanying/p/11426670.html