板子:中国剩余定理(CRT)及扩展中国剩余定理

中国剩余定理

简述

主要是用在很多算法的扩展上面,如果mo数不是素数,那么很多算法会失效,所以就把它分解质因数然后按照中国剩余定理合并即可。

本人现在不打算管证明,只需要有结论。

算法过程

设余数为c[i],模数为m[i],令M为m[i]之和
那么最终答案就是c[i](M/m[i]) inv((M/m[i]),m[i])之和modM
解是唯一的,而且由于每个mod都m个不同的情况,所以恰好可以涵盖所有情况。

代码

LL c[maxn],m[maxn],M;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    LL d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
LL getInv(LL a,LL mod)
{
    LL x,y,d;
    d=exgcd(a,mod,x,y);
    return d==1?(x%mod+mod)%mod:-1;
}
LL CRT(int n)
{
    M=1;
    for(int i=1;i<=n;i++)M*=m[i];
    LL ret=0;
    for(int i=1;i<=n;i++)
        ret=(ret+c[i] * (M/m[i]) %M * getInv(M/m[i],m[i]) )%M;
    return ret;
}

扩展中国剩余定理

简述

在mo数不两两互素的时候,就要用这个了。
这个也可以解决互素的时候的问题,思想是将方程两两合并

代码

LL gcd(LL a,LL b)
{
    return !b?a:gcd(b,a%b);
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    LL d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
LL getInv(LL a,LL mod)
{
    LL x,y;
    LL d=exgcd(a,mod,x,y);
    return d==1?(x+mod)%mod:-1;
}
LL exCRT(int n)
{
    LL m1,m2,c1,c2,d;
    for(int i=2;i<=n;i++)
    {
        m1=m[i-1],m2=m[i],c1=c[i-1],c2=c[i];
        d=gcd(m1,m2);
        if((c2-c1)%d)return -1;//此时无法合并 
        m[i] = m[i-1] * m[i] / d;
        c[i] = (c2-c1)/d * getInv(m1/d,m2/d) % ( m2 / d ) * m1 + c1;
        c[i] = ( c[i] % m[i] + m[i] ) % m[i];
    }
    return c[n];
}

最终答案就是最后一个方程的c和m

不过无论如何,mo数的乘积都不能太大了,必须存得下才可以。

你可能感兴趣的:(学习笔记/板子,模板,数学,数学板子)