ACM數論之旅9---中國剩餘定理(CRT)(壯哉我大中華╰(*°▽°*)╯)

 

中國剩餘定理,又名孫子定理o(*≧▽≦)ツide

 

能求解什麼問題呢?spa

問題:設計

一堆物品3d

3個3個分剩2個code

5個5個分剩3個orm

7個7個分剩2個blog

問這個物品有多少個ip

 

 

解這題,咱們須要構造一個答案it

咱們須要構造這個答案io

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了

 

 

 

 

 

 

 

如下抄自百度百科

中國剩餘定理給出瞭如下的一元線性同餘方程組:
中國剩餘定理1
 
中國剩餘定理說明:假設整數 m1, m2, ... , mn兩兩互質,則對任意的整數: a1, a2, ... , an,
  方程組(S)
有解,而且通解能夠用以下方式構造獲得:
  中國剩餘定理2
是整數 m1, m2, ... , mn的乘積,並設
  中國剩餘定理3
是除了 mi之外的 n- 1個整數的乘積。
  中國剩餘定理4
這個就是逆元了
  中國剩餘定理5 
通解形式爲
  中國剩餘定理6 
在模M的意義下,方程組(S) 只有一個解:
  中國剩餘定理7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
我知道大家只要代碼(*゚▽゚*),拋代碼,1,2,3,我拋
 1 //n個方程:x=a[i](mod m[i]) (0<=i<n)
 2 LL china(int n, LL *a, LL *m){
 3     LL M = 1, ret = 0;
 4     for(int i = 0; i < n; i ++) M *= m[i];
 5     for(int i = 0; i < n; i ++){
 6         LL w = M / m[i];
 7         ret = (ret + w * inv(w, m[i]) * a[i]) % M;
 8     }
 9     return (ret + M) % M;
10 } 

 

 

 

要不要來一道題試試手?

poj 1006

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

問題描述:

     人自出生起就有體力,情感和智力三個生理週期,分別爲23,28和33天。一個週期內有一天爲峯值,在這一天,人在對應的方面(體力,情感或智力)表現最好。一般這三個週期的峯值不會是同一天。如今給出三個日期,分別對應於體力,情感,智力出現峯值的日期。而後再給出一個起始日期,要求從這一天開始,算出最少再過多少天后三個峯值同時出現。

分析:

由於23 = 23

28 = 2*2*7

33 = 3*11

知足兩兩互質關係,因此直接套模板就行了

 

AC代碼:

 1 #include<cstdio>
 2 typedef long long LL;
 3 const int N = 100000 + 5;
 4 void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
 5     if (!b) {d = a, x = 1, y = 0;}
 6     else{
 7         ex_gcd(b, a % b, y, x, d);
 8         y -= x * (a / b);
 9     }
10 }
11 LL inv(LL t, LL p){//若是不存在,返回-1 
12     LL d, x, y;
13     ex_gcd(t, p, x, y, d);
14     return d == 1 ? (x % p + p) % p : -1;
15 }
16 LL china(int n, LL *a, LL *m){//中國剩餘定理 
17     LL M = 1, ret = 0;
18     for(int i = 0; i < n; i ++) M *= m[i];
19     for(int i = 0; i < n; i ++){
20         LL w = M / m[i];
21         ret = (ret + w * inv(w, m[i]) * a[i]) % M;
22     }
23     return (ret + M) % M;
24 }
25 int main(){
26     LL p[3], r[3], d, ans, MOD = 21252;
27     int cas = 0;
28     p[0] = 23; p[1] = 28; p[2] = 33;
29     while(~scanf("%I64d%I64d%I64d%I64d", &r[0], &r[1], &r[2], &d) && (~r[0] || ~r[1] || ~r[2] || ~d)){
30         ans = ((china(3, r, p) - d) % MOD + MOD) % MOD;
31         printf("Case %d: the next triple peak occurs in %I64d days.\n", ++cas, ans ? ans : 21252);
32     }
33     
34 }
View Code

 

 

 

 

 

 

 

 

 

 

 

固然,這個中國剩餘定理只是基礎,面對更強大的敵人,咱們要有更強的武器

好比,m1,m2, ... ,mn兩兩不保證互質,辣怎麼辦(っ °Д °)っ

 

 

 

別怕,看我接着拋代碼

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 typedef pair<LL, LL> PLL;
 6 PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),總共n個線性方程組 
 7     LL x = 0, m = 1;
 8     for(int i = 0; i < n; i ++) {
 9         LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
10         if(b % d != 0)  return PLL(0, -1);//答案不存在,返回-1 
11         LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
12         x = x + m*t;
13         m *= M[i]/d;
14     }
15     x = (x % m + m ) % m;
16     return PLL(x, m);//返回的x就是答案,m是最後的lcm值 
17 }

 

 

這個代碼我不給予解釋(由於我不會,哇哈哈哈╰(*°▽°*)╯)

遇到須要的題就去套模板吧

(想知道代碼原理的去百度吧,或者看《挑戰程序設計競賽》,我模板是從書裏抄來通過傑哥修改的)

 

 

 

 

 

好比poj 2891

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

【題目大意】

給出k個模方程組:x mod ai = ri。求x的最小正值。若是不存在這樣的x,那麼輸出-1.

【題目分析】

因爲這道題目裏面的ai、ri之間不知足兩兩互質的性質,因此不能用中國剩餘定理直接求解。

辣麼。。。。愉快的套這個模板吧

 

AC代碼以下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 typedef pair<LL, LL> PLL;
 6 LL a[100000], b[100000], m[100000];
 7 LL gcd(LL a, LL b){
 8     return b ? gcd(b, a%b) : a;
 9 }
10 void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
11     if (!b) {d = a, x = 1, y = 0;}
12     else{
13         ex_gcd(b, a % b, y, x, d);
14         y -= x * (a / b);
15     }
16 }
17 LL inv(LL t, LL p){//若是不存在,返回-1 
18     LL d, x, y;
19     ex_gcd(t, p, x, y, d);
20     return d == 1 ? (x % p + p) % p : -1;
21 }
22 PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),總共n個線性方程組 
23     LL x = 0, m = 1;
24     for(int i = 0; i < n; i ++) {
25         LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
26         if(b % d != 0)  return PLL(0, -1);//答案,不存在,返回-1 
27         LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
28         x = x + m*t;
29         m *= M[i]/d;
30     }
31     x = (x % m + m ) % m;
32     return PLL(x, m);//返回的x就是答案,m是最後的lcm值 
33 }
34 int main(){
35     int n;
36     while(scanf("%d", &n) != EOF){
37         for(int i = 0; i < n; i ++){
38             a[i] = 1;
39             scanf("%d%d", &m[i], &b[i]);
40         }
41         PLL ans = linear(a, b, m, n);
42         if(ans.second == -1) printf("-1\n");
43         else printf("%I64d\n", ans.first);
44     }
45 }
View Code

 

你看,全TM是套路

哇哈哈哈╰(*°▽°*)╯

哇哈哈哈╰(*°▽°*)╯

哇哈哈哈╰(*°▽°*)╯

哇哈哈哈╰(*°▽°*)╯

哇哈哈哈╰(*°▽°*)╯

哇哈哈哈╰(*°▽°*)╯

相關文章
相關標籤/搜索