中国剩余定理

https://blog.csdn.net/niiick/article/details/80229217

 

拓展中国剩余定理

注意拓展欧几里得只能解出a,b,x,y,gcd(a,b)的一组特解

 

 

模板1

long long exgcd(long long a, long long b, long long &x, long long &y) {//比较好的exgcd() 
    if (!b) {x = 1; y = 0; return a;}
    long long d = exgcd(b, a % b, y, x);
    y -= a / b * x;
     return d;
}
int china()
{
    int ans=0,lcm=1,x,y;
    for(int i=1;i<=k;++i) lcm*=b[i];
    for(int i=1;i<=k;++i)
    {
        int tp=lcm/b[i];
        exgcd(tp,b[i],x,y);
        x=(x%b[i]+b[i])%b[i];//x要为最小非负整数解
        ans=(ans+tp*x*a[i])%lcm;
    }
    return (ans+lcm)%lcm;
}

模板2:拓展定理

/*
拓展中国剩余定理,不互质的模数 
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define maxn 100005
int n;
ll m[maxn],a[maxn];//模数,余数

//拓展欧几里得,解出ax+by=gcd(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,y,x);
    y-=a/b*x;
    return d;
}

ll excrt(){//x % mi = ai 方程组 
    ll M=m[1],A=a[1],x,y;//M=lcm(m1,m2...),A= 
    for(int i=2;i<=n;i++){
        ll d=exgcd(M,m[i],x,y);
        ll c=a[i]-A;
        if(c%d)return -1;//d不能整除c,即gcd(M,m[i])不能整除 a[i]-A 
        ll mul=m[i]/d;//mi/gcd(M,mi) 
        ll u=(c/d*x%mul+mul)%mul;//当前两个方程组联立的通解u,注意要最小整数解                           
        A=A+M*u;//下一轮的A
        M=M*mul;//下一轮的M
        A%=M; 
    } 
    return (A+M)%M; 
}

int main(){
    while(cin>>n){
        for(int i=1;i<=n;i++)
            cin>>m[i]>>a[i];
        ll ans=excrt();
        cout<<ans<<endl; 
    }
} 

 

posted on 2019-02-25 23:14  zsben  阅读(170)  评论(0编辑  收藏  举报

导航