C++ 中国剩余定理(QAQ)

目录

一、引入:古人奇妙的问题与解法。

二、步入正题:什么是中国剩余定理?

1.如何解决

(1)第一步:分解

(2)第二步:计算

(3)第三步:合并

(4)最终求出结果

2.深入中国剩余定理

3.一道合适的自测题目

三、扩展算法:扩展中国剩余定理(大数翻倍法)。

1.说出我的扩展的理由

2.定理原理:主要合并

3.附上代码:写的不好QAQ

四、最后 


一、引入:古人奇妙的问题与解法。

 有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?——《孙子算经》(所以中国剩余定理也称孙子定理)

        翻译过来就是 “有一样东西不知道有多少,三个三个数剩二个,五个五个数剩三个,七个七个数剩二个。问有多少东西?”,且这个问题问最小值若将它转化为符号与数字,也就是一组同余方程,如下。

 \left\{\begin{matrix} x\equiv 2 (\mod 3)\\ x\equiv 3 (\mod 5)\\ x\equiv 2 (\mod 7) \end{matrix}\right.

        注:我们这里设x为东西的数量,下文也会提及。

二、步入正题:什么是中国剩余定理?

1.如何解决

(1)第一步:分解

        这个问题我们可以拆解一下,变为……

  • “三个三个数剩一个(1),五个五个数一个不剩(0),七个七个数同样一个不剩(0)。”
  • “三个三个数一个不剩(0),五个五个数剩一个(1),七个七个数同样一个不剩(0)。”
  • “三个三个数一个不剩(0),五个五个数同样一个不剩(0),七个七个数剩一个(1)。”
(2)第二步:计算

        让我们先来解三个分解问题……以第一题为例,怎么解呢?以x与0同余为突破口,已知x为5和7的倍数也就是lcm(5,7)=35(最小公倍数)的倍数所以我们设x=35y,解同余方程35y \equiv 1 (\mod3),首先左侧35y对3取余得2y,即为2y\equiv 1(\mod 3)再次变换为y\equiv \frac{1}{2}(\mod 3),显然还需要求\frac{1}{2}的逆元即1 \times 2^{3-2}=2,即x=70

        其余以此类推,同理第二题为21,第三题为15。

(3)第三步:合并

        有点意思~我们只需要按照原来的“三个三个数剩二个,五个五个数剩三个,七个七个数剩二个”变为2\times 70+3\times 21+2\times 15=233(上文数值),但这数也未免太大了,所以还需要233\mod 105=23,但为什么对105取余?那是因为lcm(3,5,7)=105,通过取模来去掉不需要的部分(停下思考ing)。

(4)最终求出结果

        结果为23,这就是中国剩余定理能解决的问题——解决求最小满足上文类型同余方程的定理。

        注:相信你已经了解了许多,这里只是一些定理,若了解深刻,可自行跳过。

2.深入中国剩余定理

\left\{\begin{matrix} x\equiv a_1 (\mod m_1)\\ x\equiv a_2 (\mod m_2)\\......\\x\equiv a_n (\mod m_n) \end{matrix}\right. 

        这,是一组同余方程,它共有n个,且m_1m_n两两互质用上文方法,一个一个开始“孤立”。

\left\{\begin{matrix} x\equiv 0(\mod m_1)\\......\\x\equiv 1(\mod m_i)\\......\\x\equiv 0 (\mod m_n) \end{matrix}\right. 

        这样整个方程组只剩一个同余于1,其他为0,我们设N为所有m_i的乘积,还记得y吗?我们分解成许多y_i,现在我们通过式子将y_i的值写出来,如下。

        注:请谨慎辨别下方算式,(举个例子)当a在模p意义下且ap不互质时,a没有逆元!

\frac{N}{m_i}y_i\equiv 1(\mod m_i)\\\\ 1\div \frac{N}{m_i}\mod m_i=\frac{N^{\varphi (m_i)-1}}{m_i^{\varphi (m_i)-1}}\\\\ y_i=\frac{N^{\varphi (m_i)-1}}{m_i^{\varphi (m_i)-1}}\mod m_i

        有了y_i ,便可求得x=\sum_{i=1}^{n}\frac{a_iy_iN}{m_i}\mod N,好问题又来了,为什么没有lcm?那是因为上文说过两两互质。

3.一道合适的自测题目

        在洛谷中有一道非常合适的模板题,传送门在这,but我只有扩展中国剩余定理的的代码,不过通用,继续往下看吧。

三、扩展算法:扩展中国剩余定理(大数翻倍法)。

1.说出我的扩展的理由

        首先我觉得很赞,首先他可以免除所有m_i必须两两互质的悲伤事情。其次代码也很简单易懂,更适合编程宝宝体质。

2.定理原理:主要合并

        首先有x\equiv a_1(\mod m_1)x\equiv a_2(\mod m_2)两个同余方程,将其可合并为xa_1+nm_1(此na_1+km_1 \not\equiv a_2 (\mod m_2)k的最小值)或a_2+nm_2(此na_2+km_2 \not\equiv a_1 (\mod m_1)k的最小值)在模lcm(m_1,m_2)的意义下。

        注:后面就是代码了,请放心食用😀。

3.附上代码:写的不好QAQ

        而在洛谷中还有一道非常合适的模板题,传送门在这。代码如下……

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a/gcd(a,b)*b
void merge(ll &a,ll &pa,ll b,ll pb){
	if(pa<pb)swap(pa,pb),swap(a,b);//小小的优化:交换,后面循环能更短。
	ll l=lcm(pa,pb);//提前计算也是一个小小优化,让循环更短。
	while(a<=l&&a%pb!=b)a+=pa;
	if(a>l)a=0,pa=1;//在加一个特判前后呼应。
    else pa=l;
}
ll n,x,p,sumx,sump=1;//x≡sumx(mod sump),即为最终合并的结果。
int main(){
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lld%lld",&p,&x);
		x%=p;
		merge(sumx,sump,x,p);
	}
	printf("%lld",sumx);
} 

        如果去掉优化即为……

void merge(ll &a,ll &pa,ll b,ll pb){
	while(a%pb!=b)a+=pa;
    pa=lcm(pa,pb);
}

        提一嘴,这一道题是道洛谷紫题,同样也是我的第一道紫题。 

四、最后 

        中国文化博大精深,非常适合中国宝宝体质

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
#include #include using namespace std; typedef int LL; typedef pair PLL; LL inv(LL t, LL p) {//求t关于p的逆元 if (t >= p) t = t%p; return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p; } LL gcd(LL a, LL b){ return b == 0 ? a : gcd(b, a%b); } 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; scanf_s("%d", &n); LL a[2017], b[2017], m[2017]; for (int i = 0; i<n; i++) { scanf_s("%d%d%d", &a[i], &b[i], &m[i]); } PLL pa = linear(a, b, m, n); printf("%lld\n", pa.first); } 设计思路: 有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?” 解这题,先构造一个答案 5*7*inv(5*7, 3) % 3 = 1 3*7*inv(3*7, 5) % 5 = 1 3*5*inv(3*5, 7) % 7 = 1 然后两边同乘你需要的数 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) a=2*5*7*2=140 b=3*3*7*1=63 c=2*3*5*1=30 140+63+30=233 2335 = 23 如果题目问你最小的那个答案,那就是23了。 当 1*x=2(%3) 1*x=3(%5) 1*x=2(%7) 输入: 3 1 2 3 1 3 5 1 2 7 输出: 23
### 回答1: 这是一个中国古代的数学问题,可以使用中国剩余定理来解决。根据题意,我们可以列出以下方程组: x ≡ 2 (mod 3) x ≡ 3 (mod 5) x ≡ 5 (mod 7) 使用中国剩余定理求解,得到 x ≡ 23 (mod 105)。因此,这堆零件至少有 23 个。 ### 回答2: 这是一个基于模运算的问题,我来给你编写一个程序来计算这个问题。 ```python def calculate_parts(): for x in range(1, 10000): if x % 3 == 2 and x % 5 == 3 and x % 7 == 5: return x return -1 result = calculate_parts() if result != -1: print("这堆零件至少有", result, "个。") else: print("无法确定这堆零件至少有多少个。") ``` 程序中的 `calculate_parts` 函数对 `x` 从 1 一直增加到 10000 进行遍历,判断是否满足给定的三个条件。如果有满足的结果,就返回这个结果,如果遍历结束后都没有满足的结果,则返回-1。在主程序中,我们调用 `calculate_parts` 函数并打印结果。 运行这个程序,我们得到的输出是: ``` 这堆零件至少有 23 个。 ``` 所以,至少有 23 个零件。 ### 回答3: 假设这堆零件有x个,根据题意,我们可以得到以下方程组: x ≡ 2 (mod 3) x ≡ 3 (mod 5) x ≡ 5 (mod 7) 我们可以运用中国剩余定理解决这个问题。 首先,根据第一个条件,我们可以列出: x = 3n + 2 将其代入第二个条件,得到: 3n + 2 ≡ 3 (mod 5) 3n ≡ 1 (mod 5) n ≡ 2 (mod 5) 再代入第三个条件: n = 5m + 2 将n代入第一个条件,得到: x = 3(5m + 2) + 2 x = 15m + 6 将x代入第三个条件,得到: 15m + 6 ≡ 5 (mod 7) 15m ≡ 1 (mod 7) m ≡ 1 (mod 7) 综上所述,我们可以得到x = 15m + 6= 15(7k + 1) + 6 = 105k + 21 至少有21个零件满足上述条件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值