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;
    }
  • 相关阅读:
    推荐一个wpf&sliverlight的图表控件
    数独求解
    WPF中的 CollectionChanged事件通知
    Windows 7 任务栏之缩略图预览(Thumbnail)
    把Google HK设为IE默认的搜索引擎
    F#小记——1. Hello F#
    F#小记——2. 基本数据类型
    使用异步socket的时候需要注意memory spike
    《everytime you kissed me》的中文歌词
    我回来了o(∩_∩)o...
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2841058.html
Copyright © 2011-2022 走看看