P4777 【模板】扩展中国剩余定理(EXCRT)

思路

中国剩余定理解决的是这样的问题
求x满足

\[\begin{matrix}x \equiv a_1(mod\ m_1)\\x\equiv a_2(mod\ m_2)\\ \dots\\x\equiv a_n(mod\ m_n)\end{matrix} \]

在模数互质的情况下,解为

\[x=\sum_ia_iM_iM_i^{-1}(mod M) \]

其中\(M=\prod_{i}m_i\)\(M_i=\frac{M}{m_i}\)\(M_i^{-1}\)\(M_i\)在模\(m_i\)意义下的逆元

在模数不互质的情况下,我们需要扩展中国剩余定理
设有两个同余方程

\[x \equiv a_1(mod\ m_1)\\x\equiv a_2 (mod\ m_2) \]

其中\(m_1\)\(m_2\)不互质
可得到

\[x=a_1+m_1x_1\\ x=a_2+m_2x_2 \]

所以得到

\[a_1+m_1x_1 = a_2+m_2x_2 \]

变形后有

\[m_1x_1+m_2x_2=a_2-a_1 \]

用exgcd解出最小的\(x_1\)
则有

\[x \equiv (a_1+m_1x_1)(mod\ lcm(m_1,m_2)) \]

相当于把两个式子合并在一起,EXcrt就是将所有式子合并完即可

代码

因为不想写龟速乘所以用了__int128

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int __int128
using namespace std;
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    int req=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return req;
}
int gcd(int a,int b){
    return (b==0)?a:gcd(b,a%b);
}
int lcm(int a,int b){
    return (a*b)/gcd(a,b);
}
int calc(int a,int b,int c){//ax+by=c
    int d=gcd(a,b);
    int x1,x2;
    exgcd(a,b,x1,x2);
    b/=d;
    x=(x*(c/d)%b+b)%b;
    return ans;
}
pair<int,int> merge(int a1,int m1,int a2,int m2){
    int x1=calc(m1,m2,a2-a1);
    return make_pair(x1*m1+a1,lcm(m1,m2));
}
int n,a[100100],m[100100];
signed main(){
    long long mx;
    scanf("%lld",&mx);
    n=mx;
    for(int i=1;i<=n;i++){
        scanf("%lld",&mx);
        m[i]=mx;
        scanf("%lld",&mx);
        a[i]=mx;
    }
    int mida=a[1],midm=m[1];
    for(int i=1;i<n;i++){
        pair<int,int> t= merge(mida,midm,a[i+1],m[i+1]);
        mida=t.first;
        midm=t.second;
    }
    printf("%lld\n",(long long)mida);
    return 0;
}
posted @ 2019-03-12 00:06  dreagonm  阅读(300)  评论(0编辑  收藏  举报