中国剩余定理(HDU1788)
Description
我知道部分同学最近在看中国剩余定理,就这个定理本身,还是比较简单的:
假设m1,m2,…,mk两两互素,则下面同余方程组:
x≡a1(mod m1)
x≡a2(mod m2)
…
x≡ak(mod mk)
在0<=记Mi=M/mi(1<=i<=k),因为(Mi,mi)=1,故有二个整数pi,qi满足Mipi+miqi=1,如果记ei=Mi/pi,那么会有:
ei≡0(mod mj), j!=i
ei≡1(mod mj), j=i
很显然,e1a1+e2a2+…+ekak就是方程组的一个解,这个解加减M的整数倍后就可以得到最小非负整数解。
这就是中国剩余定理及其求解过程。
现在有一个问题是这样的:
一个正整数N除以M1余(M1 - a),除以M2余(M2-a), 除以M3余(M3-a),总之, 除以MI余(MI-a),其中(a < Mi < 100 i=1,2,…I),求满足条件的最小的数。
Input
输入数据包含多组测试实例,每个实例的第一行是两个整数I(1 < I <10)和a,其中,I表示M的个数,a的含义如上所述;
紧接着的一行是I个整数M1,M2...MI,I=0 并且a=0结束输入,不处理。
Output
对于每个测试实例,请在一行内输出满足条件的最小的数。每个实例的输出占一行。
如果不存在这样的最小的数,输出-1.
Sample Input
2 1
2 3
0 0
Sample Output
5
Source
数论,欧几里得,中国剩余定理
Solution
中国剩余定理的板子题
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L
#define LL long long
using namespace std;
inline int gi() {
char cj = getchar();
int ans = 0, f = 1;
while (cj < '0' || cj > '9') {
if (cj == '-') f = -1;cj = getchar();
}
while (cj >= '0' && cj <= '9') ans = ans * 10 + cj - '0', cj = getchar();
return f * ans;
}
int I, a, r[10], m[10];
inline LL gcd(LL a, LL b) {
return (a % b == 0) ? b : gcd(b, a % b);
}
inline void exgcd(LL a, LL b, LL& x, LL& y) {
if (!b) x = 1, y = 0;
else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
}
inline LL solve() {
LL M = m[1], R = r[1];
for (int i = 2; i <= I; ++i) {
LL d = gcd(M, m[i]), c = r[i] - R;
if (c % d) return -1;
LL x, y;
exgcd(M / d, m[i] / d, x, y);
x = (c / d * x) % (m[i] / d);
R += x * M, M = M / d * m[i];
R %= M;
}
if (R < 0) R += M;
return R;
}
int main(){
freopen("CJOJ1995.in", "r", stdin);
freopen("CJOJ1995.out", "w", stdout);
while (scanf("%d %d", &I, &a) != EOF && I && a) {
memset(r, 0, sizeof(r));
memset(m, 0, sizeof(m));
for (int i = 1; i <= I; ++i) scanf("%d", &m[i]), r[i] = m[i] - a;
printf("%lld\n", solve());
}
return 0;
}