中国剩余定理

问题引入

在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。

我们把上述问题抽象出来,就是求解同余方程组:
{ x ≡ b 1 ( mod ⁡ a 1 ) x ≡ b 2 ( mod ⁡ a 2 ) x ≡ b 3 ( mod ⁡ a 3 ) ⋯ x ≡ b n ( mod ⁡ a n ) \begin{cases} x\equiv b_1(\operatorname{mod}a_1) \\x\equiv b_2(\operatorname{mod}a_2) \\x\equiv b_3(\operatorname{mod}a_3) \\ \cdots \\x\equiv b_n(\operatorname{mod}a_n) \end{cases} xb1(moda1)xb2(moda2)xb3(moda3)xbn(modan)

其中 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an互质。

解法

M = ∏ i = 1 n a i , M a i ∣ n i M=\prod_{i=1}^na_i,\frac{M}{a_i}|n_i M=i=1nai,aiMni n i ≡ b i ( mod ⁡ a i ) n_i\equiv b_i(\operatorname{mod}a_i) nibi(modai).

那么方程的一个解为:

∑ i = 1 n n i \sum_{i=1}^nn_i i=1nni

虽然解法难以想到,但原理却容易验证;我们设 x = ∑ i = 1 n n i x=\sum_{i=1}^nn_i x=i=1nni,则:

x mod ⁡ a i = ∑ j = 1 n ( n j mod ⁡ a i ) mod ⁡ a i x\operatorname{mod}a_i=\sum_{j=1}^n(n_j\operatorname{mod}a_i)\operatorname{mod}a_i xmodai=j=1n(njmodai)modai

由于对 k ≠ i k\not=i k=i都有 n k = M a k = a 1 a 2 ⋯ a k − 1 a k + 1 ⋯ a n n_k=\frac{M}{a_k}=a_1a_2\cdots a_{k-1}a_{k+1}\cdots a_n nk=akM=a1a2ak1ak+1an,其包含因子 a i a_i ai,则 n j mod ⁡ a i = 0 n_j\operatorname{mod}a_i=0 njmodai=0.

故:

x mod ⁡ a i = ∑ j = 1 n ( n j mod ⁡ a i ) mod ⁡ a i = n i mod ⁡ a i = b i x\operatorname{mod}a_i=\sum_{j=1}^n(n_j\operatorname{mod}a_i)\operatorname{mod}a_i=n_i\operatorname{mod}a_i=b_i xmodai=j=1n(njmodai)modai=nimodai=bi

那么我们如何寻找 n i n_i ni呢?我们设 n i = t M a i n_i=t\frac{M}{a_i} ni=taiM,则:

t M a i ≡ b i ( mod ⁡ a i ) t\frac{M}{a_i}\equiv b_i(\operatorname{mod}a_i) taiMbi(modai)

由欧拉定理:

( M a i ) ϕ ( a i ) ≡ 1 ( mod ⁡ a i ) \left(\frac{M}{a_i}\right)^{\phi(a_i)}\equiv1(\operatorname{mod}a_i) (aiM)ϕ(ai)1(modai)

故:

t = ( M a i ) ϕ ( a i ) − 1 t=\left(\frac{M}{a_i}\right)^{\phi(a_i)-1} t=(aiM)ϕ(ai)1

即:

n i = ( M a i ) ϕ ( a i ) n_i=\left(\frac{M}{a_i}\right)^{\phi(a_i)} ni=(aiM)ϕ(ai)

x x x的一个解为:

∑ i = 1 n n i \sum_{i=1}^nn_i i=1nni

其最小正整数解为:

∑ i = 1 n n i mod ⁡ M \sum_{i=1}^nn_i\operatorname{mod} M i=1nnimodM

这是因为 x − a i t ≡ b i ( mod ⁡ a i ) x-a_it\equiv b_i(\operatorname{mod}a_i) xaitbi(modai).

例题

https://www.luogu.com.cn/problem/P1495

#include
using namespace std;
	int n,cnt;
	int prime[500001];
	long long phi[2000001];
	bool vis[2000001];
	long long m;
	long long a[11];
	long long b[11];
long long multi(long long a,long long b,long long p)
{
     
    return ((a * b - (long long)(((long double)a * b + 0.5) / p) * p) % p + p) % p;
}
long long quickpower(long long a,long long b,long long mod)
{
     
	long long t = 1;
	while (b)
	{
     
		if (b & 1)
			t = multi(t,a,mod);
		a = multi(a,a,mod);
		b >>= 1;
	}
	return t;
}
int main()
{
     
	phi[1] = 1;
	for (int i = 2;i <= 2000000;i ++)
	{
     
		if (!vis[i])
		{
     
			prime[++cnt] = i;
			phi[i] = i - 1;
		}
		for (int j = 1;j <= cnt && prime[j] * i <= 2000000;j ++)
		{
     
			vis[i * prime[j]] = true;
			if (i % prime[j] == 0)
			{
     
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
	scanf("%d",&n);
	for (int i = 1;i <= n;i ++)
		scanf("%lld%lld",&a[i],&b[i]);
	m = 1;
	for (int i = 1;i <= n;i ++)
		m *= a[i];
	long long ans = 0;
	for (int i = 1;i <= n;i ++)
	{
     
		long long now = m / a[i];
		ans += multi(multi(b[i],now,m),quickpower(now % a[i],phi[a[i]] - 1,a[i]),m);
		ans %= m;
	}
	printf("%lld",ans);
	return 0;
}

你可能感兴趣的:(数论与数学方法)