zoukankan      html  css  js  c++  java
  • 模线性同余方程组求解

    问题:模线性同余方程组:

      x = a1 ( mod n1 )

      x = a2 ( mod n2 )

        ....

      x = ak ( mod nk )

    给定 A ( a1, a2 , ... , ak ) , N ( n1, n2, ..., nk ) 求 X 。

    通常分为两种

      一, ( Ni, Nj ) 之间两两互质

      二, ( Ni, Nj ) 之间不都互质

    一 ( Ni, Nj ) 之间两两互质

      定理( 见算法导论 P874 ):

      如果 n1, n2 , ... , nk 两两互质, n = n1*n2*..*nk ,则对任意整数 a1,a2,a3..,ak , 方程组

        x = ai ( mod ni )

      关于未知量 x 对 模n 有唯一解

    从输入 ( a1, a2, ... , ak ) 计算出 a :

           

        定义   

        定义  

    可以得到:

         

    代码模板

      a = a[i] ( mod n[i] )   ( i = 0. 1. 2. .. k )       {  n[i] 之间两两互质 }

    View Code
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    typedef long long LL;
    const int N =  1010;
    
    LL a[N], n[N], nn, k;
    
    LL Exgcd( LL a, LL b, LL &x, LL &y )
    {
        if( b == 0 ){ x = 1; y = 0; return a; } 
        LL r = Exgcd( b, a%b, x, y );
        LL t = x;
        x = y; y = t - a/b*y;
        return r;
    }
    LL mul( LL a, LL b )
    {
        LL res = 0;
        while( b )
        {
            if( b&1 ) if( (res+=a) >= nn ) res -= nn;
            a <<= 1; if( a >= nn ) a -= nn;
            b >>= 1;
        }
        return res;
    }
    LL inverse( LL A, LL B )
    {//求逆元
        LL x, y;
        Exgcd( A, B, x, y );
        return (x%B+B)%B;
    }
    LL China(){
        scanf("%lld", &k);  // k个 模同余等式
        for(int i = 0; i < k; i++)
            scanf("%lld", &a[i] );
        for(int i = 0; i < k; i++)
            scanf("%lld", &n[i] );
        nn = 1;
        for(int i = 0; i < k; i++)
            nn *= n[i];
        
        LL A = 0;
        for(int i = 0; i < k; i++)
        {
            // ci = mi * (mi^-1  mod ni )
            // ai * ci 
            LL m = nn/n[i], m1 = inverse( m, n[i] );
            LL c = m*m1;
            A = ( A + mul( a[i], c ) ) % nn;
        }
        return A;
    }
    
    int main()
    {
        printf("%lld\n",China() );    
        return 0;
    }

    二( Ni, Nj ) 之间不都互质  

      

        x = ai ( mod mi )  1 <= i <= k

        先考虑k==2的情况:

          x = a1 ( mod m1 )

          x = a2 ( mod m2 )

       方程组有解的充分必要条件是: d | (a1-a2) ,其中 d = (m1,m2)

    证明如下:

        必要性:

            设 x 是上面同余方程组的解,从而存在整数q1,q2使得x=a1+m1*q1,x=a2+m2*q2,消去x即得a1-a2 = m2q2-m1q1。由于d= GCD(m1,m2),故d | (a1-a2)。

        充分性:

            若d=GCD(m1,m2) | (a1-a2)成立,则方程m1*x + m2*y = a1-a2有解。

            设解为x0,y0。那么m2*y0 = a1-a2 ( mod m1 )

            记x1 = a2+m2*y0,可以知道 x1=a2 ( mod m2 ),且x1 = a2+m2*y0 = a2 + ( a1-a2) = a1 ( mod m1 )

            所以 x1 = a2 ( mod m2 ) = a1 ( mod m1 ) 

            所以 x = x1 ( mod GCD[m1,m2] ) 

            另外,若x1与x2都是上面同余方程组的解,则 x1 = x2 ( mod m1 ), x1 = x2 ( mod m2 ),

            由同余的性质得 x1 = x2 ( mod [m1,m2] ),即对于模[m1,m2],同余方程组的解释唯一的。

        证毕。

    C++代码模板:

      

    #include<stdio.h>
    typedef long long LL;
    LL ExGcd( LL a, LL b, LL &x, LL &y )
    {
        if( b == 0 ) { x=1;y=0; return a; }
        LL r = ExGcd( b, a%b, x, y );
        LL t = x; x = y; y = t - a/b*y;
        return r;
    }
    LL Modline( LL r[], LL a[], int n )
    {
        //  X = r[i] ( mod a[i] ) 
        LL rr = r[0], aa = a[0];
        for(int i = 1; i < n; i++ )
        {
            // aa*x + a[i]*y = ( r[i] - rr );
            LL C = r[i] - rr, x, y;
            LL d = ExGcd( aa, a[i], x, y );
            if( (C%d) != 0 ) return -1;
            LL Mod = a[i]/d;    
            x = ( ( x*(C/d)% Mod ) + Mod ) % Mod;
            rr = rr + aa*x; // 余数累加
            aa = aa*a[i]/d; // n = n1*n2*...*nk
         }
        return rr;
    }
    // test 
    int main()
    {
        int n;
        LL r[10], a[10];
        while( scanf("%d", &n) != EOF)
        {
            for(int i = 0; i < n; i++)
                scanf("%lld", &r[i] );
            for(int i = 0; i < n; i++)
                scanf("%lld", &a[i] );
            printf("%lld\n", Modline( r, a, n ) );    
        }
        return 0;
    }
  • 相关阅读:
    155. 最小栈
    160. 相交链表
    PAT 1057 Stack
    PAT 1026 Table Tennis
    PAT 1017 Queueing at Bank
    PAT 1014 Waiting in Line
    PAT 1029 Median
    PAT 1016 Phone Bills
    PAT 1010 Radix
    PAT 1122 Hamiltonian Cycle
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2841058.html
Copyright © 2011-2022 走看看