模线性方程组(中国剩余定理+通用解法)

求解

xa1 (mod m1)xa2 (mod m2)xa3 (mod m3)...xan (mod mn) { x ≡ a 1   ( m o d   m 1 ) x ≡ a 2   ( m o d   m 2 ) x ≡ a 3   ( m o d   m 3 ) . . . x ≡ a n   ( m o d   m n )

中国剩余定理

m1,m2,m3,...,mn m 1 , m 2 , m 3 , . . . , m n 两两互质,则可用中国剩余定理

M=ni=1mi M = ∏ i = 1 n m i Mi=M/mi M i = M / m i ti t i Mi M i (mod mi) ( m o d   m i ) 意义下的逆元,那么通解为

x=kM+i=1naitiMi x = k M + ∑ i = 1 n a i t i M i

解释一下: 懒得证
因为 tiMi1 (mod mi) t i M i ≡ 1   ( m o d   m i ) ,而 Mj0 (mod mi) (ji) M j ≡ 0   ( m o d   m i )   ( j ≠ i ) ,所以整个求和式子中,模 mi m i 有用的就只剩下 aitiMiai (mod mi) a i t i M i ≡ a i   ( m o d   m i ) ,对每一个 mi m i 都如此,满足所有条件。

通用解法

不要求 m1,m2,m3,...,mn m 1 , m 2 , m 3 , . . . , m n 两两互质的解法

首先考虑只有两个方程

{xa1 (mod m1)xa2 (mod m2) { x ≡ a 1   ( m o d   m 1 ) x ≡ a 2   ( m o d   m 2 )


{x=a1+m1k1x=a2+m2k2 { x = a 1 + m 1 k 1 x = a 2 + m 2 k 2

a1+m1k1=a2+m2k2 a 1 + m 1 k 1 = a 2 + m 2 k 2

m1k1m2k2=a2a1 m 1 k 1 − m 2 k 2 = a 2 − a 1

用exgcd求不定方程,将 k1 k 1 k2 k 2 解出,并带入原方程,得到一个特解 x x
可知这两个方程的通解 X X
X=x+t×lcm(m1,m2) X = x + t × l c m ( m 1 , m 2 )


Xx (mod lcm(m1,m2) ) X ≡ x   ( m o d   l c m ( m 1 , m 2 )   )

我们已经成功把两个方程合为一个,只需要继续把这个方程与方程组其他方程一一合并,就求出解了

模板题

HDU1573,求解的个数

#include
const int MAXM=13;
long long gcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    long long xx,yy,d=gcd(b,a%b,xx,yy);
    x=yy;
    y=xx-a/b*yy;
    return d;
}
long long a[MAXM],b[MAXM];
int main()
{
    int T,M;
    long long N,A,B,d,l,x,y,p,q,r;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d%d",&N,&M);
        for(int i=1;i<=M;i++)
            scanf("%I64d",a+i);
        for(int i=1;i<=M;i++)
            scanf("%I64d",b+i);
        A=a[1];B=b[1];
        bool flag=true;
        for(int i=2;i<=M;i++)
        {
            p=A;q=a[i];r=b[i]-B;
            d=gcd(p,q,x,y);
            if(r%d)
            {flag=false;break;}
            p/=d;q/=d;r/=d;
            x=x*r;
            x=(x%q+q)%q;
            l=A/d*a[i];
            B=x*A+B;
            B=(B%l+l)%l;
            A=l;
            if(B>N)break;
        }
        if(flag&&B<=N)
            printf("%I64d\n",(N-B)/A+(B!=0));
        else
            puts("0");
    }
    return 0;
}

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