中国剩余定理(CRT)/曹冲养猪【模板】

>Link

luogu P1495


>Description

求解一元线性同余方程组 { x ≡ b 1 ( m o d a 1 ) . . . . . . x ≡ b n ( m o d a n ) \left\{\begin{matrix}x\equiv b_1(mod a_1) \\ ...... \\ x\equiv b_n(mod a_n) \end{matrix}\right. xb1(moda1)......xbn(modan)
保证 a a a两两互质


>解题思路

#关于这道题
……因为用了unsigned long long调用太多内存爆了,所以只有60分,检查了好久(甚至还去对标 了)才检查出来要用longlong……

(笔记参考Bat特白

#关于中国剩余定理

孙子定理是中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国余数定理。
一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题,原文如下:
有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?即,一个整数除以三余二,除以五余三,除以七余二,求这个整数。 ——百度百科

求解一元线性同余方程组 { x ≡ 2 ( m o d 3 ) x ≡ 3 ( m o d 5 ) x ≡ 2 ( m o d 7 ) \left\{\begin{matrix}x\equiv 2(mod 3) \\ x\equiv 3(mod5) \\ x\equiv 2(mod7) \end{matrix}\right. x2(mod3)x3(mod5)x2(mod7)

将问题进行分解,使得(以下 m o d mod mod省略) { x 1 ≡ 2 ( 3 ) , x 1 ≡ 0 ( 5 ) , x 1 ≡ 0 ( 7 ) x 2 ≡ 0 ( 2 ) , x 2 ≡ 3 ( 5 ) , x 2 ≡ 0 ( 7 ) x 3 ≡ 0 ( 2 ) , x 3 ≡ 0 ( 5 ) , x 3 ≡ 2 ( 7 ) \left\{\begin{matrix}x_1\equiv 2(3),x_1\equiv 0( 5),x_1\equiv 0( 7) \\ x_2\equiv 0(2),x_2\equiv 3(5),x_2\equiv 0(7) \\x_3\equiv 0(2),x_3\equiv 0(5), x_3\equiv 2(7) \end{matrix}\right. x12(3),x10(5),x10(7)x20(2),x23(5),x20(7)x30(2),x30(5),x32(7)
此时 x = x 1 + x 2 + x 3 x=x_1+x_2+x_3 x=x1+x2+x3 x x x的性质依然满足

再将问题进行分解,看 x 1 x_1 x1如何求
y 1 ≡ 1 ( 3 ) , y 1 ≡ 0 ( 5 ) , y 1 ≡ 0 ( 7 ) y_1\equiv 1(3),y_1\equiv 0( 5),y_1\equiv 0( 7) y11(3),y10(5),y10(7)
那么 x 1 = 2 ∗ y 1 x_1=2*y_1 x1=2y1

这样求出所有的 y y y x = 2 ∗ y 1 + 3 ∗ y 2 + 2 ∗ y 3 x=2*y_1+3*y_2+2*y_3 x=2y1+3y2+2y3
但是此时 x x x还不是最小解, x x x要不断减去 3 , 5 , 7 3,5,7 3,5,7的最小公倍数直到不能减(呃好吧其实就是直接取模

那么如何求 y y y??
因为 y 1 ≡ 1 ( 3 ) , y 1 ≡ 0 ( 5 ) , y 1 ≡ 0 ( 7 ) y_1\equiv 1(3),y_1\equiv 0( 5),y_1\equiv 0( 7) y11(3),y10(5),y10(7),所以 y 1 y_1 y1一定是 5 5 5 7 7 7的公倍数,我们设 y 1 = 35 t y_1=35t y1=35t
那么现在就变成了 35 t ≡ 1 ( 3 ) 35t\equiv 1(3) 35t1(3),可以转化成 35 t − 1 = 3 k 35t-1=3k 35t1=3k
再转化一下: 35 t − 3 k = 1 35t-3k=1 35t3k=1,这不就是exgcd吗!直接开始扩欧
(因为题目保证 a i a_i ai a j a_j aj互质,所以我们可以扩欧)


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define N 100000
using namespace std;

int n;
LL a[N], b[N], M, ans, m;

void ex_gcd (LL aa, LL bb, LL &x, LL &y)
{
	if (!bb) {x = 1, y = 0; return;}
	LL X = x, Y = y;
	ex_gcd (bb, aa % bb, X, Y);
	x = Y;
	y = X - (aa / bb) * Y;
}

int main()
{
	scanf ("%d", &n);
	M = 1;
	for (int i = 1; i <= n; i++)
	{
		scanf ("%lld%lld", &a[i], &b[i]);
		M *= a[i];
	}
	for (int i = 1; i <= n; i++)
	{
		m = M / a[i];
		LL x = 0, y = 0;
		ex_gcd (a[i], m, x, y);
		if (y <= 0) y += a[i];
		ans += m * y * b[i];
	}
	printf ("%lld", ans % M);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值