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

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

题目链接:luogu P1495

题目大意

给你一些条件,要你找最小的 x,使得满足它被一些数取模的答案是要求的数。
且模数相互都是互质的。
在这里插入图片描述

思路

我们考虑我们先让每个式子单独找数满足,这个很好找,我们可以找到 \(x_1,x_2,...x_n\)
那你考虑搞 \(x_1+x_2\),看他能不能同时满足两个式子。
那你要想,那你为了不破坏余数,那你 \(x_2\) 要是 \(a_1\) 的倍数,\(x_1\) 要是 \(a_2\) 的倍数。

那你以此类推,变成所有的加起来,那就是要 \(x_1\)\(a_2,a_3,...,a_n\) 的倍数,\(x_2\)\(a_1,a_3,...,a_n\) 的倍数,.……。
这个很好找,就先搞出所有 \(a\) 的最小公倍数,然后除去 \(a_i\) 就行。

那接着你 \(x_i\) 还要满足模 \(a_i\)\(b_i\),那这一步要怎么处理呢?
那你要求 \(\text{LCM}\times m\equiv b_i(\bmod\ a_i)\)
不如先求 \(\text{LCM}\times m\equiv 1(\bmod\ a_i)\),然后再拿结果乘 \(b_i\)
然后不难看出 \(m\) 就是 \(\text{LCM}\) 关于 \(a_i\) 的逆元。

那你就求得了 \(x_1,x_2,...,x_n\)
加起来就是一个解了。

但是我们要求最小解,那我们考虑通解。
那模 \(a_i\) 的余数什么时候回循环一次呢?(完全匹配的那种)
不难想到是 \(\text{lcm}\{a_i\}\) 个循环一次。
那就把答案模 \(LCM\) 就可以了。

代码

#include<cstdio>
#define ll long long

using namespace std;

int n;
ll a[11], b[11], LCM, X;

ll gcd(ll x, ll y) {
	if (!y) return x;
	return gcd(y, x % y);
}

ll exgcd(ll a, ll b, ll &x, ll &y) {//exgcd 求逆元
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	
	ll re = exgcd(b, a % b, y, x);
	y -= x * (a / b);
	return re;
}

int main() {
	scanf("%d", &n);
	LCM = 1;
	for (int i = 1; i <= n; i++) {
		scanf("%lld %lld", &a[i], &b[i]);
		LCM = LCM * a[i] / gcd(LCM, a[i]);//求积
	}
	
	for (int i = 1; i <= n; i++) {
		ll mi = LCM / a[i];
		ll x = 0, y = 0;
		exgcd(mi, a[i], x, y);
		X += b[i] * mi * ((x % a[i] + a[i]) % a[i]);//注意 x 有可能是负数
	}
	
	printf("%lld", X % LCM);
	
	return 0;
}
posted @ 2021-08-24 08:59  あおいSakura  阅读(118)  评论(0编辑  收藏  举报