中国剩余定理和扩展中国剩余定理原理证明:请看这里。
自己手撸的,不保证完全正确,仅供参考。
中国剩余定理代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n;
LL a[N], m[N];
LL exgcd(LL a, LL b, LL &x, LL &y)
{
if(!b) { x = 1; y = 0; return a; }
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL CRT(LL a[], LL m[], int n)//a (mod m)
{
LL M = 1, res = 0;
for(int i = 1; i <= n; i ++) M *= m[i];
for(int i = 1; i <= n; i ++)
{
LL Mi = M / m[i], x, y; //x存储Mi的逆元
LL d = exgcd(Mi, m[i], x, y);
res = (res + a[i] * Mi * x) % M;
}
return (res + M) % M;
}
int main()
{
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
cin >> n;
for(int i = 1; i <= n; i ++)
cin >> a[i] >> m[i];
cout << CRT(a, m, n) << endl;
return 0;
}
扩展中国剩余定理代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL exgcd(LL a, LL b, LL &x, LL &y)
{
if(!b) { x = 1, y = 0; return a; }
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL EXCRT(LL a[], LL m[], int n)
{
bool succes = true;
LL x; //存放解
for(int i = 2; i <= n; i ++) //将第2~n个方程都合并到第1个方程上面
{
LL k1, k2;
LL d = exgcd(m[1], m[i], k1, k2); //第1个和第i个合并
if((a[i]- a[1]) % d) //方程无解
{
succes = false;
break;
}
k1 *= (a[i] - a[1]) / d; //这里求出来的k1并不是原来方程的k1,需要在乘一下
//k1 + m[i]/d是k1的通解,在所有可以选择的k1中取一个最小的,防止溢出
k1 = (k1 % (m[i] / d) + m[i] / d) % (m[i] / d);
x = k1 * m[1] + a[1]; //存下来该组解
//接下来将合并后的方程的a和m存放到a[i]和m[1]中.
a[1] = k1 * m[1] + a[1];
m[1] = abs(m[1] / d * m[i]); //d可能是负数,所以加上abs
}
return succes ? (x % m[1] + m[1]) % m[1] : -1;
}