中国剩余定理学习笔记

CRT

求一个最小的 x 使得

{xa1 (mod b1)xa2 (mod b2)...xan (mod bn)

其中 b1,b2,...,bn 互质


考虑将 x 拆成 x1+x2+...+xn

使 x1 满足:

  • 它是 b2,b3,...,bn 的倍数
  • x1a1(mod b1)

使 x2 满足:

  • 它是 b1,b3,b4,...,bn 的倍数
  • x2a2(mod b2)

以此类推

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

那么显然有 x=i=1nximodi=1nbi


然后我们考虑怎么求 xi

首先肯定要求出 pai=bi

然后有一个比较显然的结论 设 x1(mod mod)
axa(mod mod)

所以我们要先求出一个 xi1(mod bi)

x1 为例 首先 x1 一定是 pai/b1 的整数倍

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

我们设这个倍数为 k 发现有 k×pai/b11(mod b1)

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

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

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

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

洛谷板子题: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 使得

{xa1 (mod b1)xa2 (mod b2)...xan (mod bn)

不保证 b1,b2,...,bn 互质


咕了 有时间再填

posted @   Steven24  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 聊一聊 C#异步 任务延续的三种底层玩法
· 上位机能不能替代PLC呢?
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· .NET Core:架构、特性和优势详解
· 一个适用于 .NET 的开源整洁架构项目模板
点击右上角即可分享
微信分享提示