扩展中国剩余定理

扩展中国剩余定理( e x c r t \boldsymbol{excrt} excrt)是用来解决同余方程组的问题的,我们之前说过中国剩余定理,但是他有一个应用的限制就是 l c m { p i } = 1 \boldsymbol{lcm\{p_i\}=1} lcm{ pi}=1,但是如果某个恶心的出题人要求这个 l c m { p i } ≠ 1 \boldsymbol{lcm\{p_i\}\neq 1} lcm{ pi}=1怎么办呢?你就可以用扩展中国剩余定理吊打他

e x c r t \boldsymbol{excrt} excrt跟普通的 c r t \boldsymbol{crt} crt的思想有一个很大的不同, c r t \boldsymbol{crt} crt使用的是构造法,而 e x c r t \boldsymbol{excrt} excrt是直接暴力

还是对于这样的一个方程

{ x ≡ a 1   m o d   p 1 x ≡ a 2   m o d   p 2 ⋯ x ≡ a n   m o d   p n \begin{cases} \boldsymbol{x\equiv a_1\ mod\ p_1} \\ \boldsymbol{x\equiv a_2\ mod\ p_2} \\ \qquad \cdots \\ \boldsymbol{x\equiv a_n\ mod\ p_n} \\ \end{cases} xa1 mod p1xa2 mod p2xan mod pn
其中 l c m { p i } ≥ 1 \boldsymbol{lcm\{p_i\}\geq 1} lcm{ pi}1
我们可以考虑这样一个思路,把问题转化成两个方程的求解,然后把解出来的结果合并成一个新的方程,然后再和下一个求解,以此类推,通过 n − 1 \boldsymbol{n-1} n1次合并,我们就可以得出结果了


引理:
对于两个方程
{ x ≡ a 1   m o d   p 1 x ≡ a 2   m o d   p 2 ⋯ x ≡ a n   m o d   p n \begin{cases} \boldsymbol{x\equiv a_1\ mod\ p_1} \\ \boldsymbol{x\equiv a_2\ mod\ p_2} \\ \qquad \cdots \\ \boldsymbol{x\equiv a_n\ mod\ p_n} \\ \end{cases} xa1 mod p1xa2 mod p2xan mod pn
如果对于 x ′ \boldsymbol{x^\prime} x如果满足前 k \boldsymbol{k} k个方程,那么 s . t .   x = x ′ + t ⋅ l c m { p j } , x \boldsymbol{s.t.\ x=x^\prime+t\cdot lcm\{p_j\},x} s.t. x=x+tlcm{ pj},x为第 k + 1 \boldsymbol{k+1} k+1个方程的解,其中 t ∈ Z + , j ∈ [ 1 , k ] \boldsymbol{t\in Z^+,j\in[1,k]} tZ+,j[1,k],证明也是显然的,就是同余的基本定义


有了这个,我们接下来就只需要求出 t \boldsymbol{t} t的最小整数解了,设 l c m { p j } = M \boldsymbol{lcm\{p_j\}=M} lcm{ pj}=M,我们的问题就转化成了求 x ′ + t M ≡ a k + 1   m o d   p k + 1 \boldsymbol{x^\prime+tM\equiv a_{k+1}\ mod\ p_{k+1}} x+tMak+1 mod pk+1
移项,可以得到 t M ≡ a k + 1 − x ′   m o d   p k + 1 \boldsymbol{tM\equiv a_{k+1}-x^\prime\ mod\ p_{k+1}} tMak+1x mod pk+1 t \boldsymbol{t} t的最小整数解,那么也就是求方程
a x ≡ p   m o d   b \boldsymbol{ax\equiv p\ mod\ b} axp mod b
的最小整数解
变形,可以得到 a x + b y = p \boldsymbol{ax+by=p} ax+by=p
那么我们可以先利用扩展欧几里得求出 a x ′ + b y ′ = g c d ( a , b ) \boldsymbol{ax^\prime+by^\prime=gcd(a,b)} ax+by=gcd(a,b)的解
那么 x \boldsymbol{x} x就等于 x ′ p g c d ( a , b ) \boldsymbol{\frac{x^\prime p}{gcd(a,b)}} gcd(a,b)xp
那么通过这个方法,令 M = a , a k + 1 − x ′ = p , p k + 1 = b \boldsymbol{M=a,a_{k+1}-x^\prime=p,p_{k+1}=b} M=a,ak+1x=p,pk+1=b,从而求出 x \boldsymbol{x} x t \boldsymbol{t} t
同时这里我们也可以发现,这组同余方程有解的条件是 g c d ( M , p k + 1 ) ∣ a k + 1 − x ′ \boldsymbol{gcd(M,p_{k+1})|a_{k+1}-x^\prime} gcd(M,pk+1)ak+1x,否则无解


然后就是代码了,这里放上的是洛谷模板题的代码,因为模板题保证有解,所以不用判断无解的情况,但是如果题目没有说明应该放上去

#include 
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=1e5+5;

template<typename T> void read(T &x){
     
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

# define int long long

int n;
int a[N],b[N],x,y;

int mul(int a,int b,int p){
     
    int res=0;
    while(b){
     
        if(b&1)res+=a,res%=p;
        a=a+a,a%=p;
        b>>=1;
    }
    return res;
}

int exgcd(int a,int b,int &x,int &y){
     
    if(!b){
     
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int z=y;
    y=x-a/b*y;
    x=z;
    return d;
}

int excrt(){
     
    int ans=a[1],M=b[1];
    Rep(i,2,n){
     
        int GCD=exgcd(M,b[i],x,y);
        int val=((a[i]-ans)%b[i]+b[i])%b[i];
        x=(x%b[i]+b[i])%b[i];
        int t=mul(x,val,b[i])/GCD;
        int lM=M;
        M=M/GCD*b[i];
        ans=ans+mul(lM,t,M);
        ans%=M;
    }
    return ans;
}

signed main()
{
     
    read(n);
    Rep(i,1,n)read(b[i]),read(a[i]);
    printf("%lld\n",excrt());
    return 0;
}

你可能感兴趣的:(#,中国剩余定理,#,乘法逆元)