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

数论--中国剩余定理

时间:2017-10-07 17:46:27      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:block   def   std   target   最小   tar   ble   百度   模板   

中国剩余定理:

国务院:中国油气人均剩余可采存储量仅为世界平均的6%...

咳咳,不对,不是这个

 

中国剩余定理,又名孙子定理:

听说过韩信点兵吗?

韩信带1500名兵士打仗,战死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信很快说出人数:1049。

韩信一定是读过《孙子算经》的,

书里面有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”

也就是:

一堆物品,

3个3个分剩2个,

5个5个分剩3个,

7个7个分剩2个,

问这个物品有多少个?

解这题,我们需要构造一个答案

我们需要构造这个答案

5*7*inv(5*7,  3) % 3  =  1

3*7*inv(3*7,  5) % 5  =  1

3*5*inv(3*5,  7) % 7  =  1

这3个式子对不对,别告诉我逆元你忘了(*′?`*),忘了的人请翻阅前几章复习

 

然后两边同乘你需要的数

2 * 5*7*inv(5*7,  3) % 3  =  2

3 * 3*7*inv(3*7,  5) % 5  =  3

2 * 3*5*inv(3*5,  7) % 7  =  2

 

令 

a = 2 * 5*7*inv(5*7,  3) 

b = 3 * 3*7*inv(3*7,  5) 

c = 2 * 3*5*inv(3*5,  7) 

那么

a % 3 = 2

b % 5 = 3

c % 7 = 2

其实答案就是a+b+c

因为

a%5 = a%7 = 0 因为a是5的倍数,也是7的倍数

b%3 = b%7 = 0 因为b是3的倍数,也是7的倍数

c%3 = c%5 = 0 因为c是3的倍数,也是5的倍数

所以

(a + b + c) % 3 = (a % 3) + (b % 3) + (c % 3) = 2 + 0 + 0 = 2

(a + b + c) % 5 = (a % 5) + (b % 5) + (c % 5) = 0 + 3 + 0 = 3

(a + b + c) % 7 = (a % 7) + (b % 7) + (c % 7) = 0 + 0 + 2 = 2

你看你看,答案是不是a+b+c(??ω?)??,完全满足题意

但是答案,不只一个,有无穷个,每相隔105就是一个答案(105 = 3 * 5 * 7)

 

根据计算,答案等于233,233%105 = 23

如果题目问你最小的那个答案,那就是23了

(233怎么算的呢?

    a=2*5*7*2=140;

    b=3*3*7*1=63;

    c=2*3*5*1=30;

 140+63+30=233;

   hhh2333333333333333,答案233出来了吧,hhh,不会算逆元的小伙伴该回去复习逆元了!)

 

以下抄自百度百科

中国剩余定理给出了以下的一元线性同余方程组:
技术分享
 
中国剩余定理说明:假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,
 方程组(S)
有解,并且通解可以用如下方式构造得到:
 技术分享
是整数m1,m2, ... ,mn的乘积,并设
 技术分享
是除了mi以外的n- 1个整数的乘积。
 技术分享
这个就是逆元了
 技术分享 
通解形式为
 技术分享 
在模M的意义下,方程组(S)只有一个解:
 技术分享
 
那么代码来了:
 1 #include<cstdio>
 2 
 3 typedef long long LL;
 4 
 5 LL inv(LL t, LL p) {//求t关于p的逆元 
 6     if(t>=p)
 7     t=t%p;
 8     return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
 9 }
10 
11 //n个方程:x=a[i](mod m[i]) (0<=i<n)
12 LL china(int n, LL m[], LL a[]){
13     LL M = 1, ret = 0;
14     for(int i = 0; i < n; i ++) M *= m[i];
15     for(int i = 0; i < n; i ++){
16         LL w = M / m[i]; 
17         ret = (ret + w * inv(w, m[i]) * a[i]) % M;
18     }
19     return (ret + M) % M;
20 }
21 int main(){
22     int n;
23     LL m[2000],a[2000];
24     scanf("%d",&n);
25     for(int i=0;i<n;i++)
26     {
27         scanf("%d%d",&m[i],&a[i]);
28      } 
29      printf("%lld\n",china(n,m,a));
30 }

3个式子:

x%3=2

x%5=3

x%7=2

求x;

运行程序,输入

3

3 2

5 3

7 2

试试看答案是不是23

 

告诉你一个好消息,上面这个中国剩余定理只是基础,2333333333,是要求m数组里面的元素两两互质的!

那如果不一定是呢?怎么办?

上模板吧:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 typedef pair<LL, LL> PLL;
 6 
 7 LL inv(LL t, LL p) {//求t关于p的逆元 
 8     if(t>=p)
 9     t=t%p;
10     return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
11 }
12 
13 PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组 
14     LL x = 0, m = 1;
15     for(int i = 0; i < n; i ++) {
16         LL a = A[i] * m, b = B[i] - A[i]*x, d = __gcd(M[i], a);
17         if(b % d != 0)  return PLL(0, -1);//答案不存在,返回-1 
18         LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
19         x = x + m*t;
20         m *= M[i]/d;
21     }
22     x = (x % m + m ) % m;
23     return PLL(x, m);//返回的x就是答案,m是最后的lcm值 
24 }
25 
26 int main()
27 {
28     int n;
29     scanf("%d",&n);
30     LL a[2017],b[2017],m[2017];
31     for(int i=0;i<n;i++)
32     {
33         scanf("%d%d%d",&a[i],&b[i],&m[i]);
34     }
35     PLL pa=linear(a,b,m,n);
36     printf("%lld\n",pa.first);
37 }

1*x=2(%3)

1*x=3(%5)

1*x=2(%7)

输入:

3

1 2 3

1 3 5

1 2 7

输出:

23

 

有兴趣的可以去试试这道题

poj 2891

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

 

数论--中国剩余定理

标签:block   def   std   target   最小   tar   ble   百度   模板   

原文地址:http://www.cnblogs.com/eastblue/p/7635006.html

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