中国剩余定理学习笔记

CRT

求一个最小的 \(x\) 使得

\(\begin{cases} x \equiv a_1\ ({\rm mod}\ b_1) \\ x\equiv a_2\ ({\rm mod}\ b_2) \\ ... \\ x \equiv a_n\ ({\rm mod}\ b_n)\end{cases}\)

其中 \(b_1, b_2, ..., b_n\) 互质


考虑将 \(x\) 拆成 \(x_1 + x_2 + ... + x_n\)

使 \(x_1\) 满足:

  • 它是 \(b_2, b_3, ..., b_n\) 的倍数
  • \(x_1 \equiv a_1 (\text{mod }b_1)\)

使 \(x_2\) 满足:

  • 它是 \(b_1, b_3, b_4, ..., b_n\) 的倍数
  • \(x_2 \equiv a_2 (\text{mod }b_2)\)

以此类推

又因为 \(b\) 是互质的 所以任何几个 \(b\) 的 lcm 直接就是它们的乘积

那么显然有 $x = \sum\limits_{i = 1}^n x_i \mod \prod\limits_{i = 1}^n b_i $


然后我们考虑怎么求 \(x_i\)

首先肯定要求出 \(pai = \prod b_i\)

然后有一个比较显然的结论 设 \(x \equiv 1 (\text{mod } mod)\)
\(a x \equiv a (\text{mod } mod)\)

所以我们要先求出一个 \(x_i' \equiv 1 (\text{mod } b_i)\)

\(x_1\) 为例 首先 \(x_1'\) 一定是 \(pai / b_1\) 的整数倍

一个很暴力的想法就是枚举这个倍数 直到余数为 \(1\)

我们设这个倍数为 \(k\) 发现有 \(k \times pai / b_1 \equiv 1 (\text{mod }b_1)\)

我们发现实际上 \(k\) 就是 \(pai / b_1\) 在模 \(b_1\) 意义下的逆元

  • 注意 \(b_i\) 不一定为质数 所以要用扩欧求逆元 并且记得判负

从中也可以看出为什么要求所以 \(b\) 互质
因为实质上你的扩欧方程是 \(pai / b_i \times k + b_i \times y = 1\)
根据裴蜀定理 只有 \(\gcd (pai / b_i, b_i) = 1\)\(b_i\) 与其他所有 \(b\) 都互质的时候才有解

  • 注意求出来 \(k\) 之后我们还要再乘上 \(a_i\) 并且这个过程需要开快速乘

洛谷板子题:P3868 [TJOI2009] 猜数字

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 11;
ll a[N], b[N];
ll pai = 1;
int k;
ll ans;

ll ksc(ll x, ll y) {
	ll ret = 0;
	while (y) {
		if (y & 1) ret = (ret + x) % pai;
		x = (x + x) % pai;
		y >>= 1;
	}
	return ret;
}

void exgcd(ll a, ll b, ll &x, ll &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return;
	}
	exgcd(b, a % b, x, y);
	ll z = x;
	x = y;
	y = z - (a / b) * y;
}

int main() {
	scanf("%d", &k);
	for (int i = 1; i <= k; ++i) scanf("%lld", &a[i]);
	for (int i = 1; i <= k; ++i) {
		scanf("%lld", &b[i]);
		pai *= b[i];
	}
	
	for (int i = 1; i <= k; ++i) {
		ll x, y;
		exgcd(pai / b[i], b[i], x, y);
		x = (x % b[i] + b[i]) % b[i];
		a[i] = (a[i] % b[i] + b[i]) % b[i];
		ans = (ans + ksc(pai / b[i] * x, a[i])) % pai;
	}
	
	printf("%lld", ans);
	
	return 0;
}

exCRT

求一个最小的 \(x\) 使得

\(\begin{cases} x \equiv a_1\ ({\rm mod}\ b_1) \\ x\equiv a_2\ ({\rm mod}\ b_2) \\ ... \\ x \equiv a_n\ ({\rm mod}\ b_n)\end{cases}\)

不保证 \(b_1, b_2, ..., b_n\) 互质


咕了 有时间再填

posted @ 2023-09-08 13:47  Steven24  阅读(20)  评论(0编辑  收藏  举报