扩展CRT学习笔记

中国剩余定理是用来解同余方程组的

${x} \equiv {r_1} (mod \;p_1)$

${x} \equiv {r_2} (mod \;p_2)$

$...$

${x} \equiv {r_n} (mod \;p_n)$

但是构造法只能求解$p$都互质的情况,那当$p$不互质怎么办办勒把出题人吊起来打一顿就好了

然而NOI时好像不能跑出考场阿掉出题人啊~~~

 

那我们可以考虑两个同余方程

${x} \equiv {r_1} (mod \;p_1)$

${x} \equiv {r_2} (mod \;p_2)$

我们试图把它们合并成一个,如果成功了,我们就可以把n个方程合并成一个,然后就可以出解啦

怎么合并勒?

发现$x=r_1+k_1*p_1=r_2+k_2*p_2$

那么${k_1*p_1}\equiv{r_2-r_1}(mod\;p_2)$

那么把等式全除以$gcd(p_1,p_2)$,当$r_2-r_1$不能被整除时,就无解了

否则我们把$p_1$和$p_2$都除以$gcd(p_1,p_2)$后就互质了,就可以求逆元啦,然后就可以求出$k_1$啦

那么新的方程就是${x} \equiv {r_1+k_1*p_1} (mod \;\frac{(p_1)(p_2)}{(gcd(p_1,p_2)})$

 

我的模板(由于种种原因,我加了龟速快速乘防止爆long long)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,i,j,a[500000],b[500000];
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
int exgcd(int a,int b,int &x,int &y)
{
    int t=a;
    if(!b)x=1,y=0;else t=exgcd(b,a%b,y,x),y-=(a/b)*x;
    return t;
}
int mul(int a,int b,int mod)
{
    a%=mod,b%=mod;
    a=(a+mod)%mod,b=(b+mod)%mod;
    int ans=0;
    while(b)
    {
        if(b%2)ans=(ans+a)%mod;
        a=a*2%mod;b=b/2;
    }
    return ans;
}
int CRT(int *re,int *mod,int n)
{
    int r=0,m=1;
    for(int i=0;i<n;i++)
    {
        int g=gcd(m,mod[i]),x,y;
        if((re[i]-r)%g)return -1;
        int inv;exgcd(m/g,mod[i]/g,x,y);inv=x;
        int M=m/gcd(m,mod[i])*mod[i];
        int k1=mul((re[i]-r)/g,inv,M);
        r+=mul(k1,m,M);
        m=M;r=(r+m)%m;
    }
    return r;
}
main()
{
    scanf("%lld",&n);
    for(i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]);
    printf("%lld",CRT(b+1,a+1,n));
    return 0;
}

 

posted @ 2018-07-25 16:07  橙子用户  阅读(218)  评论(0编辑  收藏  举报