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 ", x); return 0; }