• 模线性方程组


    韩信点兵

    问题:给定了n组除数m[i]和余数r[i],通过这n组(m[i],r[i])求解一个x,使得x mod m[i] = r[i]

    解:

      一开始就直接求解多个方程组的解,比较困难,所以我们从 n = 2 开始递推

      已知:

    x mod m[1] = r[1]
    x mod m[2] = r[2]

      所以存在两个数, k[1], k[2]

    x = k[1]*m[1] + r[1]
    x = k[2]*m[2] + r[2]

      因为值相同,所以:

            k[1]*m[1] + r[1] = k[2]*m[2] + r[2]
    =>    k[1]*m[1] - k[2]*m[2] = r[2] - r[1]

      令 A = m[1], B = m[2], C = r[2] - r[1], x = k[1], y = k[2]  则上式变为 Ax + By = C

      则是扩展欧几里德,可以看我之前的一篇博客http://www.cnblogs.com/ygdblogs/p/5476395.html

      由于每两个方程可以合并成一个,连续操作,转化为一个方程,即可求解多个方程组的解

      伪代码:

    M = m[1], R = r[1]
    For i = 2 .. N 
        d = gcd(M, m[i])
        c = r[i] - R
        If (c mod d) Then    // 无解的情况
            Return -1
        End If
        (k1, k2) = extend_gcd(M / d, m[i] / d)    // 扩展欧几里德计算k1,k2
        k1 = (c / d * k1) mod (m[i] / d)    // 扩展解系
        R = R + k1 * M        // 计算x = m[1] * k[1] + r[1]
        M = M / d * m[i]     // 求解lcm(M, m[i])
        R %= M             // 求解合并后的新R,同时让R最小
    End For        
    If (R < 0) Then 
        R = R + M
    End If
    Return R

      源码:

    #include<stdio.h>
    #include<iostream>
    typedef long long ll;
    ll m[1010], r[1010], x, y;
    
    ll gcd(ll a,ll b){
        if(a%b == 0) return b;
        return gcd(b, a%b);
    }
    
    void extend_gcd(ll a,ll b){
        if(b==0){
            x=1;
            y=0;
        }
        else{
            extend_gcd(b,a%b);
            ll t=x;
            x=y;
            y=t-(a/b)*x;
        }
    }
    
    int main(){
        int n;
        ll a, b, c, ans, r1;
        scanf("%d",&n);
        for(int i =0; i<n; i++)
            scanf("%lld%lld",&m[i],&r[i]);
        a = m[0], r1 = r[0];
        for(int i=1; i<n; i++){
            b = m[i];
            c = r[i] - r1;
            ll d = gcd(a, b);
            if(c%d){
                ans=-1;
                break;
            }
            else{
                ll a1 = a/d;
                ll b1 = b/d;
                ll c1 = c/d;
                extend_gcd(a1,b1);
                ll x1 = (x*c1)%b1;
                if(x1< 0)
                  x1 += b1;
                r1 = a*x1 + r1;
                a = a1*b;
                ans = r1;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
    转载请注明出处:http://www.cnblogs.com/ygdblogs
  • 相关阅读:
    数组去重复的时候遇到length变成1 的bug
    js中的setTimeout第三个参数
    Maven安装过程
    wordpress 修改过程
    CentOS 6.5 安装 MySQL5.6 并用Navicat for MySQL 连接
    解决安装WordPress主题及插件需要输入FTP问题
    mysql语句记录
    How to set a MySQL root user password in MAC OSX
    【转】解决Windows不能在本地计算机启动apache tomcat
    近期要看文章(20150105)
  • 原文地址:https://www.cnblogs.com/ygdblogs/p/5503792.html
Copyright © 2020-2023  润新知