在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以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} ⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x≡b1(moda1)x≡b2(moda2)x≡b3(moda3)⋯x≡bn(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,aiM∣ni且 n i ≡ b i ( mod a i ) n_i\equiv b_i(\operatorname{mod}a_i) ni≡bi(modai).
那么方程的一个解为:
∑ i = 1 n n i \sum_{i=1}^nn_i i=1∑nni
虽然解法难以想到,但原理却容易验证;我们设 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=1∑n(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=a1a2⋯ak−1ak+1⋯an,其包含因子 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=1∑n(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) taiM≡bi(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=1∑nni
其最小正整数解为:
∑ i = 1 n n i mod M \sum_{i=1}^nn_i\operatorname{mod} M i=1∑nnimodM
这是因为 x − a i t ≡ b i ( mod a i ) x-a_it\equiv b_i(\operatorname{mod}a_i) x−ait≡bi(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;
}