首页 > 代码库 > POJ 2891 Strange Way to Express Integers 中国剩余定理MOD不互质数字方法

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\n");            return;        }        ansx = x * mm + rr;        mm = lcm(mm, mod[i]);        rr = ansx % mm;    }    printf("%lld\n", rr);    return;}int main() {#ifdef local    freopen("data.txt","r",stdin);#endif    while(scanf("%d", &n) != EOF && n) {        work();    }    return 0;}
View Code

 

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