码迷,mamicode.com
首页 > 其他好文 > 详细

中国剩余定理总结

时间:2014-11-10 21:56:17      阅读:372      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   ar   os   sp   for   on   

                                                                                                                              中国剩余定理总结


  当你遇到x == c (mod p) 要你求解x的时候,是不是很容易的想到了这样转换---> x - py = c运用extgcd得到答案。但是现在如果有很多个x呢?如:

                                          x == c1(mod p1)

                                          x == c2(mod p2)

                                           ...............................

                                         x == cn(mod pn)

   这时候你要如何求解呢?肯定不能像上面一样吧!

 其实这类问题有一个专门的算法成为孙子定理流行叫法是中国剩余定理(China Remainder Theorem)。

一般一个算法的出现肯定有其的约束条件吧?对啊。这个普通版的CRT的限制是模之间是两两互素的。但是不互难道就不能求解了吗?当然也可以,这时候就要用CRT的扩展版。下面分别举例来说明和训练。


一、当模两两互质的条件下

题目链接:Click Here~

分解出题目的意思:现在假设总共有X 头猪,每个猪圈Y头猪。

那么显然可以得到 ---> X - Y*ai = bi 根据同余式的定义对式子转换---> X == bi(mod ai)。结果很裸了。套模板的时候。


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

typedef long long LL;
const int MAXN = 10 + 10;
int n,a[MAXN],m[MAXN];

void extgcd(LL a,LL b,LL& d,LL& x,LL& y){
    if(!b) { d = a; x = 1; y = 0; }
    else { extgcd(b,a%b,d,y,x); y -= x*(a/b); }
}

LL china(int n,int *a,int *m){
   LL M = 1,d,y,x = 0;
   for(int i = 0;i < n;++i) M *= m[i];
   for(int i = 0;i < n;++i){
      LL w = M / m[i];
      extgcd((LL)m[i],w,d,d,y);
      x = (x + y*w*a[i]) % M;
   }
   return (x+M)%M;
}

int main()
{
    while(~scanf("%d",&n)){
        for(int i = 0;i < n;++i)
            scanf("%d%d",&m[i],&a[i]);
        printf("%I64d\n",china(n,a,m));
    }
    return 0;
}

 

二、当模两两不互质

题目链接:Click Here~  

题目很简单就不解释了。最要来看看如何转换成CRT来求解。现在我们假设每堆硬币都有Y个,则可以得到以下等式:1*X - Y*Mi = Ai ---> X == Ai(mod Mi) 下面就是模板问题了。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
int n,times;

LL A[MAXN],r[MAXN];   //x == Ai(mod ri)

LL gcd(LL a,LL b){
   return b?gcd(b,a%b):a;
}

void ex_gcd(LL a,LL b,LL& d,LL& x,LL& y){
    if(!b) { d = a; x = 1; y = 0; }
    else { ex_gcd(b,a%b,d,y,x); y -= x*(a/b); }
}

void read_case(){
    scanf("%d",&n);
    lcm = 1;
    for(int i = 1;i <= n;++i){
        scanf("%lld",&A[i]);
        lcm = lcm / gcd(lcm,A[i]) * A[i];
    }
    for(int i = 1;i <= n;++i) scanf("%lld",&r[i]);
}

void solve(){
   read_case();
   
   LL lcm;
   LL a,b,c,d,x,y;
   for(int i = 2;i <= n;++i){
       a = A[1],b = A[i],c = r[i] - r[1];
       ex_gcd(a,b,d,x,y);
       if(c % d){printf("-1\n"); return;}
       LL b1 = b / d;
       x *= c / d;
       x = (x % b1 + b1) % b1;
       r[1] = A[1] * x + r[1];
       A[1] = A[1]*(A[i] / d);
   }
   if(r[1] == 0) printf("%lld\n",lcm);
   else printf("%lld\n",r[1]);
}

int main(){
    int T;
    times = 0;
    scanf("%d",&T);
    while(T--){
       printf("Case %d: ",++times);
       solve();
    }
    return 0;
}



中国剩余定理总结

标签:style   blog   http   io   ar   os   sp   for   on   

原文地址:http://blog.csdn.net/zhongshijunacm/article/details/40982927

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!