搞搞中国剩余定理和它的扩展

中国剩余定理

解决同余方程组的相关问题,然而貌似扩展一下发生质变?

同余方程组问题

\[x\equiv a_1 \mod m_1 \]

\[x\equiv a_2 \mod m_2 \]

\[\dots\dots\]

\[x\equiv a_n \mod m_n \]

求解满足上述同余方程组的\(x\)

中国剩余定理(CRT)

  • 要求:模数\(m_1,m_2,\dots,m_n\) 必须互质(为什么呢?)
  • CRT告诉我们,这个方程组在模\(M=m_1*m_2*\dots*m_n\) 意义下的解是唯一的。
  • CRT还告诉我们这个解为\[x\equiv a_1 M_1 M_1^{-1}+a_2 M_2M_2^{-1}+\dots+a_n M_nM_n^{-1} \mod M\]其中\(M_i=M/m_i\) ,而\(M_i^{-1}\) 是模\(m_i\) 意义下的逆元。
  • \[x=\sum a_i\frac{M}{m_i}inv(\frac{M}{m_i},\,m_i)\]
  • 这个解是构造性的解,可以验证其是满足上述方程组的。
  • 为什么两两互质?逆元的要求!
const int maxn=1000;
int a[maxn];
int m[maxn];

int CRT(int n){
    int M=1;
    int ans=0;
    for(int i=1;i<=n;i++){
        M*=m[i];
    }
    for(int i=1;i<=n;i++){
        int x,y;
        int Mi=M/m[i];
        exgcd(Mi,m[i],x,y);
        ans=(ans+a[i]*Mi*x)%M;
    }
    if(ans<0)ans+=M;
    return ans;
}

扩展中国剩余定理(exCRT)

  • 模数\(m_1,m_2,\dots,m_n\) 不互质的时候也可以有解啦!
  • 考虑一下同余方程组仅有两个方程的情况。
  • \[x\equiv c_1 \mod m_1 \]\[x\equiv c_2 \mod m_2\]
  • \[x=c_1 +m_1k_1$ ,$x=c_2 +m_2k_2\]
  • \[c_1 +m_1k_1=c_2 +m_2k_2\]
  • \[m_1k_1 =c_2-c_1+m_2k_2\]
  • 这个方程有解的充要条件是\[\gcd(m_1,m_2)\,|\,(c_2-c_1)\]
  • \[\frac{m_1k_1}{\gcd(m_1,m_2)} =\frac{c_2-c_1}{\gcd(m_1,m_2)}+\frac{m_2k_2}{\gcd(m_1,m_2)}\]
  • \[\frac{m_1k_1}{\gcd(m_1,m_2)} \equiv\frac{c_2-c_1}{\gcd(m_1,m_2)}\mod \frac{m_2}{\gcd(m_1,m_2)}\]
  • \[k_1\equiv inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}\mod \frac{m_2}{\gcd(m_1,m_2)}\]
  • \(inv(a,b)\) 表示\(a\) 在模\(b\) 意义下的逆元
  • \[k_1=inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}+K* \frac{m_2}{\gcd(m_1,m_2)}\]
  • 带回\(x=c_1 +m_1k_1\)
  • \[x=c_1 +m_1*(inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}+K* \frac{m_2}{\gcd(m_1,m_2)})\]
  • \[x\equiv c_1 +m_1*inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}\mod \frac{m_1m_2}{\gcd(m_1,m_2)}\]
  • 到这里,我们已经完成了两个同余方程的整合!有形式\(x\equiv a \mod m\)
  • 其中\[a=c_1 +m_1*inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}\] \[m=\frac{m_1m_2}{\gcd(m_1,m_2)}\]
  • 反复重复以上操作!(二合一,加一,合一,······)
const int maxn=1000;
int a[maxn];
int m[maxn];

int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}

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 tmp=x;
    x=y;
    y=tmp-a/b*y;
    return d;
}

int inv(int a,int mod){
    int x,y;
    int d=exgcd(a,mod,x,y);
    return d==1?(x%mod+mod)%mod:-1;
}

int exCRT(int n){
    int m1, m2, c1, c2, d;
    for(int i=2;i<=n;i++){
        m1=m[i-1];//这里是与前一个进行合并
        m2=m[i];
        c1=a[i-1];
        c2=a[i];
        d=gcd(m1,m2);
        if((c2-c1)%d!=0){
            return -1;//无法合并
        }
        m[i]=m[i-1]*m[i]/d;//公式(倒数第二个)
        a[i]=c1+m1*inv(m1/d,m2/d)%(m2/d)*(c2-c1)/d;//公式(倒数第二个)
        a[i]=(a[i]%m[i]+m[i])%m[i];
    }
    return a[n];
}

猜你喜欢

转载自www.cnblogs.com/tongseli/p/11614623.html