中国剩余定理+扩展

最近有点不妙啊。- -。

前提知识:扩展欧几里得,乘法逆元,快速幂等。

中国剩余定理。CRT。

现在看来比较简单了。
他用来处理一堆形如
x≡ai(mod mi)的同余方程。
最后求x。
要用这个定理的前提是mi两两互质。
(注意我设的未知量的大小写)
定理内容:首先令M=m1 m2 。。。。。(所有m乘起来)。
然后,令Mi=M/mi,Ri为 Mi在模mi意义下的逆元。
那么ans=sigma ai *Mi *Ri mod(M)

为啥呢?
让我通俗易懂(高大上)地证明一波。

对于一个数aj来说,它对答案贡献的就是aj *Mj *Rj(看上面)。
那么这个数在mod (mj)意义下它就是aj 因为Rj是Mj在mj意义下的逆元乘起来为1,而对于非aj的数来说,比如ak,它对答案贡献就是ak * Mk * Rk,Mk里面含有mj,所以它在mod (mj)意义下就是0,其他所有非aj的数都如此,那么可以保证求出的答案在mod(mj)意义下就是aj,同理,对于所有的同余方程都如此。

下面上一份代码:

#include
#define N 100005
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return d;
}

int inverse(int a,int m){
    int x,y;
    int d=exgcd(a,m,x,y);
    if(d!=1)return -1;
    else return (x%m+m)%m;
}//求逆元 
int a[N],m[N],num;
int crt(){
    int M=1,ans=0; 
    for(int i=1;i<=num;i++)
    M*=m[i];
    for(int i=1;i<=num;i++){
        int Mi=M/m[i],Ri=inverse(Mi,m[i]);
        ans=(ans+1LL*a[i]*Mi*Ri%M)%M;
    }
    return ans;
}

int main(){
    scanf("%d",&num);
    for(int i=1;i<=num;i++)
    scanf("%d%d",&a[i],&m[i]);
    printf("%d\n",crt());
    return 0;
}

对于扩展版本就是mi两两不互质的情况。
我们考虑合并两个方程。就是对于两个方程。
x≡ai(mod mi)
x≡aj(mod mj)
改写为aj+mj*t1=ai+mi*t2
求解这个方程带入原式得到x,把新的m变为mi和mj的最小公倍数,因为mi和mj都可以整除它们最小公倍数,而x可以在这个基础上+-公倍数都不会对原来两个方程的答案造成影响,

代码懒得给了~~~。

你可能感兴趣的:(总结)