ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)

 

中国剩余定理,又名孙子定理o(*≧▽≦)ツ

能求解什么问题呢?

问题:

一堆物品

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了

以下抄自百度百科

中国剩余定理给出了以下的一元线性同余方程组:
 
中国剩余定理说明:假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,

 方程组(S)

有解,并且通解可以用如下方式构造得到:

 

是整数m1,m2, ... ,mn的乘积,并设

 

是除了mi以外的n- 1个整数的乘积。

 

这个就是逆元了

  
通解形式为

  

在模M的意义下,方程组(S)只有一个解:

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
我知道你们只要代码(*゚▽゚*),抛代码,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代码:

#include<cstdio>
typedef long long LL;
const int N = 100000 + 5;
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p){//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
LL china(int n, LL *a, LL *m){//中国剩余定理
LL M = 1, ret = 0;
for(int i = 0; i < n; i ++) M *= m[i];
for(int i = 0; i < n; i ++){
LL w = M / m[i];
ret = (ret + w * inv(w, m[i]) * a[i]) % M;
}
return (ret + M) % M;
}
int main(){
LL p[3], r[3], d, ans, MOD = 21252;
int cas = 0;
p[0] = 23; p[1] = 28; p[2] = 33;
while(~scanf("%I64d%I64d%I64d%I64d", &r[0], &r[1], &r[2], &d) && (~r[0] || ~r[1] || ~r[2] || ~d)){
ans = ((china(3, r, p) - d) % MOD + MOD) % MOD;
printf("Case %d: the next triple peak occurs in %I64d days.\n", ++cas, ans ? ans : 21252);
}

}

 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 }

当然,这个中国剩余定理只是基础,面对更强大的敌人,我们要有更强的武器

比如,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代码如下:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
LL a[100000], b[100000], m[100000];
LL gcd(LL a, LL b){
return b ? gcd(b, a%b) : a;
}
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p){//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
LL x = 0, m = 1;
for(int i = 0; i < n; i ++) {
LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
if(b % d != 0) return PLL(0, -1);//答案,不存在,返回-1
LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
x = x + m*t;
m *= M[i]/d;
}
x = (x % m + m ) % m;
return PLL(x, m);//返回的x就是答案,m是最后的lcm值
}
int main(){
int n;
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; i ++){
a[i] = 1;
scanf("%d%d", &m[i], &b[i]);
}
PLL ans = linear(a, b, m, n);
if(ans.second == -1) printf("-1\n");
else printf("%I64d\n", ans.first);
}
}

 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 }

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL, LL> PLL;
LL a[100000], b[100000], m[100000];
LL gcd(LL a, LL b){
return b ? gcd(b, a%b) : a;
}
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p){//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
PLL linear(LL A[], LL B[], LL M[], int n) {//求解A[i]x = B[i] (mod M[i]),总共n个线性方程组
LL x = 0, m = 1;
for(int i = 0; i < n; i ++) {
LL a = A[i] * m, b = B[i] - A[i]*x, d = gcd(M[i], a);
if(b % d != 0) return PLL(0, -1);//答案,不存在,返回-1
LL t = b/d * inv(a/d, M[i]/d)%(M[i]/d);
x = x + m*t;
m *= M[i]/d;
}
x = (x % m + m ) % m;
return PLL(x, m);//返回的x就是答案,m是最后的lcm值
}
int main(){
int n;
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; i ++){
a[i] = 1;
scanf("%d%d", &m[i], &b[i]);
}
PLL ans = linear(a, b, m, n);
if(ans.second == -1) printf("-1\n");
else printf("%I64d\n", ans.first);
}
}

acm数论之旅--中国剩余定理的更多相关文章

  1. (暂时弃坑)(半成品)ACM数论之旅18---反演定理 第二回 Mobius反演(莫比乌斯反演)((づ ̄3 ̄)づ天才第一步,雀。。。。)

    莫比乌斯反演也是反演定理的一种 既然我们已经学了二项式反演定理 那莫比乌斯反演定理与二项式反演定理一样,不求甚解,只求会用 莫比乌斯反演长下面这个样子(=・ω・=) d|n,表示n能够整除d,也就是d ...

  2. ACM数论之旅17---反演定理 第一回 二项式反演(神说要有光 于是就有了光(´・ω・`))

    终于讲到反演定理了,反演定理这种东西记一下公式就好了,反正我是证明不出来的~(-o ̄▽ ̄)-o 首先,著名的反演公式 我先简单的写一下o( ̄ヘ ̄*o) 比如下面这个公式 f(n) = g(1) + g ...

  3. acm数论之旅---扩展欧几里得算法

    度娘百科说: 首先, ax+by = gcd(a, b) 这个公式肯定有解 (( •̀∀•́ )她说根据数论中的相关定理可以证明,反正我信了) 所以 ax+by = gcd(a, b) * k 也肯定 ...

  4. ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)

    中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 7个7个分剩2个 问这个物品有多少个 解这题,我们需要构造一个答案 我们需要构造这 ...

  5. acm数论之旅--数论四大定理

    ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我)   (本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威 ...

  6. 数论之同余性质 线性同余方程&拔山盖世BSGS&中国剩余定理

    先记录一下一些概念和定理 同余:给定整数a,b,c,若用c不停的去除a和b最终所得余数一样,则称a和b对模c同余,记做a≡b (mod c),同余满足自反性,对称性,传递性 定理1: 若a≡b (mo ...

  7. ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我)

    (本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威尔逊定理 2.欧拉定理 3.孙子定理(中国剩余定理) 4.费马小定理 (提 ...

  8. [TCO 2012 Round 3A Level3] CowsMooing (数论,中国剩余定理,同余方程)

    题目:http://community.topcoder.com/stat?c=problem_statement&pm=12083 这道题还是挺耐想的(至少对我来说是这样).开始时我只会60 ...

  9. 数论E - Biorhythms(中国剩余定理,一水)

    E - Biorhythms Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Subm ...

随机推荐

  1. date-fns时间库的基本使用

    在react中使用date-fns: import sub_days from 'date-fns/sub_days'; import start_of_week from 'date-fns/sta ...

  2. api接口出现Provisional headers are shown,

    问题分析:根据反馈可以知道,发起请求,但服务器未及时响应,原因可能是超时,或者被拦截

  3. C++-POJ2955-Brackets[DP]

    题意就是,找出最长合法子括号序列 容易想到设f[l][r]为l~r的最长合法子括号序列的长度 然后从短的状态往长的状态枚举,不断更新答案就可以了 //#include<bits/stdc++.h ...

  4. 题解 CF712C 【Memory and De-Evolution】

    看到题我第一反应就是while循环 但是我竟然想正着推,失败,卡了十几分钟 后来我回来看到第三组测试数据 想到倒推 但是没坚持 于是我又卡了很久 过会我又回来想 AC了... 这个故事告诉我们,要努力 ...

  5. CentOS安装RabbitMQ-yum

    CentOS安装RabbitMQ----yum安装 一.安装erlang 由于CentOS没有erlang源,需用 第三方源(http://rpmfusion.org/Configuration) 1 ...

  6. pytest学习4-fixtures

    源码注释: def fixture(scope="function", params=None, autouse=False, ids=None, name=None): &quo ...

  7. Xampp在Mac下报403的问题

    将httpd.conf里的 User daemonGroup daemon 改为 User myusername(当前使用的用户名)Group admin

  8. Leetcode 74. 搜索二维矩阵 C+

    二分法,先对行二分找出结果可能存在的行,再对这一行二分查找.O(Log m+Log n),m.n分别为矩阵的高和宽. class Solution { public: bool searchMatri ...

  9. 集成unittest做接口测试

    unittest接口测试 上篇已经讲了接口测试的做法,利用的是postman工具,工具始终是工具,它有一定的局限性,比如测试数据的存放,断言的方法以及上下接口关联使用灵活性.python对http接口 ...

  10. layui下select禁止点击

    layui下拉选择框select禁止点击_设置禁用_设置不可操作的实现方法 直接上代码: <form class="layui-form"> <!-- 提示:如果 ...