• POJ 2891 Strange Way to Express Integers 中国剩余定理MOD不互质数字方法


    http://poj.org/problem?id=2891

    7
    11323 9793
    5537 4754
    21538 10901
    16118 203
    2082 1209
    22929 9510
    16541 15898

    
    

    4
    18373 16147
    8614 14948
    8440 17480
    22751 21618
    6
    19576 8109
    18992 24177
    9667 17726
    16743 19533
    16358 12524
    8280 22731
    4
    9397 38490
    22001 25094
    33771 38852
    19405 35943

    ans

    32439
    13052907343337200
    -1
    78383942913636233

    题目mod的数字并不互质,那怎么办呢?

    记mod[i]表示第i个mod的数字,r[i]表示余数,那么观察前两项

    总有X = k1 * mod[1] + r[1];

          X = k2 * mod[2] + r[2];

    那么k1 * mod[1] - k2 * mod[2] = r[2] - r[1]

    这是可以用扩展欧几里德算法求得最小的解k1 (k1可以等于0,不一定要>0,我就是规定满足k1>0后不断溢出,所以wa)

    那么得到满足前两个数字的解是(就是满足%mod[1] = r[1] , %mod[2] = r[2])的解。ansx = k1 * mod[1] + r[1]

    然后往下合并

    怎么往下合并呢?

    就是把前面两条等式,变成了 % lcm(mod[1], mod[2]) = rr了,这个rr可以自己解出来,ansx % lcm(mod[1], mod[2])就是了

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    
    const int maxn = 500 + 20;
    LL mod[maxn];
    LL r[maxn];
    LL gcd(LL n, LL m) {
        if (n % m == 0) return m;
        else return gcd(m, n % m);
    }
    LL lcm(LL n, LL m) {
        return n / gcd(n, m) * m;
    }
    LL exgcd (LL a,LL mod,LL &x,LL &y) {
        //求解a关于mod的逆元     ★:当且仅当a和mod互质才有用
        if (mod==0) {
            x=1;
            y=0;
            return a;//保留基本功能,返回最大公约数
        }
        LL g=exgcd(mod,a%mod,x,y);
        LL t=x;    //这里根据mod==0  return回来后,
        x=y;    //x,y是最新的值x2,y2,改变一下,这样赋值就是为了x1=y2
        y=t-(a/mod)*y;    // y1=x2(变成了t)-[a/mod]y2;
        return g;            //保留基本功能,返回最大公约数
    }
    bool get_min_number (LL a,LL b,LL c,LL &x,LL &y) {  //得到a*x+b*y=c的最小整数解
        LL abGCD = gcd(a,b);
        if (c % abGCD != 0) return 0;//不能整除GCD的话,此方程无解
        a /= abGCD;
        b /= abGCD;
        c /= abGCD;
        LL tx,ty;
        exgcd(a,b,tx,ty); //先得到a*x+b*y=1的解,注意这个时候gcd(a,b)=1
        x = tx * c;
        y = ty * c; //同时乘上c,c是约简了的。得到了一组a*x + b*y = c的解。
        LL haveSignB = b;
        if (b < 0) b = -b;   //避免mod负数啊
        x = (x % b + b) % b; //最小解
    //    if (x == 0) x = b; //避免x = 0不是"正"整数  不要用这个,溢出
        y = (c - a * x) / haveSignB;
        return 1;//1代表可以
    }
    int n;
    void work () {
        for (int i = 1; i <= n; ++i) {
            scanf("%lld%lld", &mod[i], &r[i]);
        }
        LL mm = mod[1];
        LL rr = r[1];
        LL ansx = 0;
        for (int i = 2; i <= n; ++i) {
            LL x, y;
            int ret = get_min_number(mm, -mod[i], r[i] - rr, x, y);
            if (ret == 0) {
                printf("-1
    ");
                return;
            }
            ansx = x * mm + rr;
            mm = lcm(mm, mod[i]);
            rr = ansx % mm;
        }
        printf("%lld
    ", rr);
        return;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        while(scanf("%d", &n) != EOF && n) {
            work();
        }
        return 0;
    }
    View Code

    为什么rr就是最小解呢?余数当然是最小的解啊。。。

  • 相关阅读:
    retain,copy,mutableCopy的区别
    xcode 添加mainWindow.xib
    ios 协议代理
    mysql基础
    mysql常用语句(转)
    mysql的13个使用技巧(转)
    mysql性能优化教程(转)
    mysql学习资源(转)
    find命令详解(转)
    vim基础操作(转)----附vim壁纸
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5924834.html
Copyright © 2020-2023  润新知