首页 > 代码库 > 中国剩余定理

中国剩余定理


中国剩余定理用于求解 x≡ai(mod mi),其中mi两两互质,x有唯一解。

令M为mi的乘积,wi = M/mi,wi关于模mi的逆元为pi,即满足wi*pi + mi*qi = 1.

则上述方程组等价于 x≡ w1*p1*a1 + w2*p2*a2 +......+wk*pk*ak(mod M)................................................................①


验证: 当M = m1时, (w2*p2*a2 +......+wk*pk*ak)%m1 = 0,那么上式变为 x≡w1*p1*a1(mod m1),又因为w1的关于模m1的逆元是p1,那么进一步化简为x≡a1(mod m1)。类比当M = m2,m3,,,,mk时,①式都是成立的。


因此求x,只需求w1*p1*a1 + w2*p2*a2 +......+wk*pk*ak(mod M),其中wi,ai是已知的,pi可根据方程wi*pi + mi * qi = 1用扩展欧几里得求出。


#include <stdio.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include <limits.h>
#include <algorithm>
#define LL long long
#define _LL __int64
using namespace std;

LL extend_gcd(LL a, LL b, LL &x, LL &y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	LL d = extend_gcd(b,a%b,x,y);
	LL t = x;
	x = y;
	y = t - a/b*y;
	return d;
}

LL CRT(LL *p, LL *o, int num)
{
	LL x,y;
	LL ans = 0,n = 1;
	for(int i = 0; i < num; i++)
		n *= o[i];

	for(int i = 0; i < num; i++)
	{
		extend_gcd(n/o[i],o[i],x,y);
		x = (x + o[i])%o[i];
		ans = (ans + n/o[i]*x*p[i])%n;
	}
	return ans;
}

int main()
{
    int n;
    LL a[15],m[15];
    while(~scanf("%d",&n))
    {
        for(int i = 0; i < n; i++)
            scanf("%lld %lld",&a[i],&m[i]);
        printf("%lld\n",CRT(a,m,n));
    }
	return 0;
}