个人理解---中国剩余定理
a1 r1 a2 r2 a3 r3
有一个数x,除以3余2,除以5余3, 除以7余2,求x的最小值;
计算过程是:(70 * 2 + 21 * 3 + 15 * 2 ) % 105 = 23.
(N1 * R1 + N2 * R2 + N3 * R3) % N = x.
其中 70(N1)是5(A2)和7(A3)的最小公倍数,对3(A1)求余为1;
21(N2)是3(A1)和7(A3)的最小公倍数,对5(A2)求余为1;
15(N3)是3(A1)和7(A2)的最小公倍数,对5(A3)求余为1;
N 为3(A1),5(A2),7(A3)的最小公倍数.
那么就可以推广到:
x % A1 = R1,
x % A2 = R2,
x % A3 = R3,
x % A4 = R4,
......
x % An = Rn.
求最小的x,其中Ai为素数;
N = A1 * A2 * A3 * A4 * ... * An;
所以我们要求出Ni, Ni=A1 * A2 *...* Ai-1 * Ai+1 *... * An * Ki, 根据Ni%Ai=1来确定Ki的值
x = (R1*N1 + R2*N2 + R3*N3 + ... + Rn*Nn)% N ;因为要求的是:最小整数解,所以对N求余即可;
下面关键就是求Ni,即求Ki;
因为N是所有A的乘积,Ni为除Ai外的所有Ai的倍数,所以:
Ni = N / Ai * K;(K为任意整数);---------式1;
又因为Ni对Ai求余为1,所以:
Ni = Ai * K0 + 1;(K0为任意整数);-------式2;
从上面可以看出只要我们求出K或者K0就可以求出Ni了;
由1,2式得N / Ai * K = Ai * K0 + 1
化简得:(N/Ai)*K + (-Ai)K0 = 1;
不难看出上式满足ax + by = gcd(a, b)
由上面的分析知道N/Ai与-Ai一定互质即gcd(N/Ai, -Ai) = gcd(N/Ai, Ai) = 1;
所以可以用扩展欧几里德来求解K和K0;
#include<stdio.h>
#define MAXN 22
int n, N0;
void ex_gcd(int a, int b, int &x, int &y)
{
if(b==0)
{
x = 1;
y = 0;
return ;
}
ex_gcd(b, a%b, x, y);
int temp = x;
x = y;
y = temp - a/b * y;
if(a*b<0)///如果a和b异号那么x和y取反;理由不太清楚;
{
x = -x;
y = -y;
}
}
int China(int N[], int A[], int R[])
{
int x = 0;
for(int i=1; i<=n; i++)
{
int K, K0;
ex_gcd(N0/A[i], -A[i], K, K0);
N[i] = A[i] * K0 + 1; ///或者 N[i] = N0/A[i] * K;
x = (x + N[i] * R[i] + N0) % N0;
}
return (x+N0)%N0;///防止出现负数;
}
int main()
{
int A[MAXN], R[MAXN], N[MAXN];
scanf("%d", &n);
N0 = 1;
for(int i=1; i<=n; i++)
{
scanf("%d %d", &A[i], &R[i]);
N0 *= A[i];
}
int x = China(N, A, R);
printf("%d\n", x);
return 0;
}

浙公网安备 33010602011771号