中国剩余定理(限制条件:模为两两互质)

中国剩余定理其实很早我们都接触过,在初中甚至小学的时候我们都有可能看到过这样的问题:有n个东西,三个人分剩两个,五个人分剩三个,七个人分剩两个,求n最少是多少。

求解这个问题古人就已经想到了很好的解决办法。
我们由题意易知:
x=2(mod)3;
x=3(mod)5;
x=2(mod)7;

如果x=n1+n2+n3。
n1是5,7的倍数,且n1%3=2。
n2是3,7的倍数,且n2%5=3。
n3是3,5的倍数,且n3%7=2。
故我们可以知道n1+n2+n3定是x的一个解。

那么怎么求n1,n2,n3呢?
我们由逆元知道。

(57) inv(57,3) = 1(mod)3;
(3
7)* inv(37, 5) = 1(mod)5;
(3
5)* inv(3*5, 7) = 1(mod)7;

故n1 = 2 * 5*7*inv(5*7,3),n2 = 3 * 3*7*inv(3*7, 5),n3 = 2 * 3*5*inv(3*5, 7)  。

因为,中国剩余定理的模都是两两互质,必有逆元。用扩展欧几里得算法就可以求解,于是我们最后将求得的n1,n2,n3相加,最后的答案就是n=(n1+n2+n3)mod(lcm(3,5,7))。

中国剩余定理_#define


扩展下,一共有n对方程,

x = p[i] mod m[i]

设M = m[i]数组的积,设Mi = M / mi,即为除了mi其他数的积,设ti = Mi 在mod mi的逆元,即Mi * ti =1mod mi。


中国剩余定理_中国剩余定理_02


中国剩余定理_#define_03

模板 51nod1079

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define d(x) cout << (x) << endl
#pragma GCC diagnostic error "-std=c++11"
using namespace std;
typedef long long ll;
const int mod = 1000000009;
const int N = 20;

ll p[N], m[N];
int n;

void exgcd(ll a, ll b, ll &x, ll &y)
{ //exgcd求乘法取模运算的逆元
if (!b)
{
y = 0, x = 1;
return;
}
else
{
exgcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
}
}

ll crt(void)
{
ll M = 1, ans = 0;
for (int i = 0; i < n; i++)
{
M *= m[i];
}
for (int i = 0; i < n; i++)
{
ll mi = M / m[i], x, y;
exgcd(mi, m[i], x, y);
ans = (ans + p[i] * x * mi) % M;
}
if (ans < 0)
{
ans += M;
}
return ans;
}

int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%lld%lld", &m[i], &p[i]);
}
printf("%lld\n", crt());
return 0;
}