【学习笔记】中国剩余定理

声明:本博客所有随笔都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。

前言

找了一些博客,好像都是直接给你结论然后再分析,顺序让我有点难接受,打算按自己的思路理一遍

这篇博客写的好棒!!

————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

一、概念

给定 (n) 组非负整数 (a_i), (b_i),求解关于 (x) 的方程组的最小非负整数解。

[egin{cases}xequiv b_1(mod a_1)\xequiv b_2(mod a_2)\...\xequiv b_n(mod a_n)end{cases} ]

保证 (b_i)(b_j) 互质

————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

二、分析

方程有点多,我们先从一个方程解起

对于方程 (x_iequiv b_i(mod a_i)) ,很显然 (x_i = a_i + b_i * k ( k in Z ))

那么对于 (n) 个方程就有 (n)(x),我们想想能否将它们合并?

例如,对于 (s = x_i + x_j),我们想要 (s) 仍然满足 (sequiv b_i(mod a_i))(sequiv b_j(mod a_j))

显然,(( x_i + k * b_i ) \% b_i = a_i),所以只要 (x_j)(b_i) 的倍数即可,同样,(x_i) 也得为 (b_j) 的倍数

把它推广一下,即当 (s = x_1 + x_2 + x_3 + ... + x_n) 时,为满足 (s \% b_i = a_i),则 (x_1,x_2...x_{i-1},x_{i+1}...x_n) 得为 (b_i) 的倍数

整理一下可得,所有的 (x_i) 得为 (b_j ( j eq i )) 的倍数,同时 (x_i \% b_i = a_i)

还有一个小技巧就是,找 (x_i) 的时候可以先找 (prodlimits_{j eq i}a_j)(b_i) 下的逆元(这里要用扩展欧几里得),再乘以 (a_i)

————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

三、结论

转载自文章开头的博客

————————————————————————————٩(ˊᗜˋ)و✧*————————————————————————————

四、(Code)

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

#include<bits/stdc++.h>
#define F(i, x, y) for(int i = x; i <= y; ++ i)
#define ll long long
using namespace std;
ll read();
const int N = 15;
int n;
ll a[N], b[N];
ll mod = 1, ans, x, y;
int exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b == 0)
	{
		x = 1, y = 0; 
		return a;
	}
	int r = exgcd(b, a % b, x, y), tmp = y;
	y = x - a / b * y, x = tmp;
	return r;
}
int main()
{
	n = read();
	F(i, 1, n) b[i] = read(), a[i] = read(), mod *= b[i];
	F(i, 1, n) 
	{
		exgcd(mod / b[i], b[i], x, y);
		ans = ((ans + a[i] * x * (mod / b[i])) % mod + mod) % mod;
	}
	printf("%lld
", ans % mod);
} 
ll read()
{
	ll x = 0; 
	char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x;
}
原文地址:https://www.cnblogs.com/Bn_ff/p/12716103.html