中国剩余定理
实质就是解 n n n次互质的方程,然后分别乘以他们的取模剩余量,然后相加得到答案,这里就不展开叙述。
typedef long long ll;
const int N = 1e3 + 10;
int a[N], b[N], n;
void exgcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1;
y = 0;
return ;
}
exgcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
return ;
}
void solve() {
ll m = 1, x, y, ans = 0;
for(int i = 1; i <= n; i++)
m *= b[i];
for(int i = 1; i <= n; i++) {
ll t = m / b[i];
exgcd(t, b[i], x, y);
ans = (ans + x * t * a[i]) % m;
}
ans = (ans + m) % m;
printf("%lld\n", ans);
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d %d", &a[i], &b[i]);//a[i]是余数,b[i]是模数。
solve();
return 0;
}
中国剩余定理拓展
思路
我们规定 b [ i ] b[i] b[i]时余数, a [ i ] a[i] a[i]是模数。
显然对于一个方程我们可以直接得到 a n s 1 = b [ 1 ] ans_1 = b[1] ans1=b[1],用这个答案去求解第二个方程,解显然可以描述为 a n s 2 = a n s 1 + k ∗ a [ 1 ] ans_2 = ans_1 + k * a[1] ans2=ans1+k∗a[1],所以第二个方程的解可以如下推理:
a n s 1 + k ∗ a [ 1 ] ≡ b [ 2 ] ( m o d a [ 2 ] ) ans1 + k * a[1] \equiv b[2] \pmod {a[2]} ans1+k∗a[1]≡b[2](moda[2])
k ∗ a [ 1 ] ≡ b [ 2 ] − a n s 1 ( m o d a [ 2 ] ) k * a[1] \equiv {b[2] - ans1} \pmod{a[2]} k∗a[1]≡b[2]−ans1(moda[2])
所以我们只要解的 k k k就行,无非就是做一次 e x g c d exgcd exgcd嘛,得到
a n s 2 = a n s 1 + k ∗ a [ 1 ] ans_2 = ans_1 + k * a[1] ans2=ans1+k∗a[1]
如果继续拓展下去,我们显然有 a n s k = i = 1 i = k − 1 l c m ∗ k + a n s k − 1 ans_k = _{i = 1} ^ {i = k - 1} lcm * k + ans_{k - 1} ansk=i=1i=k−1lcm∗k+ansk−1,也就是把上面推导的式子换成前 k − 1 k - 1 k−1项的 l c m lcm lcm。
P4777 【模板】扩展中国剩余定理(EXCRT)
裸题。
/*
Author : lifehappy
*/
// #pragma GCC optimize(2)
// #pragma GCC optimize(3)
// #include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <cmath>
#define mp make_pair
#define pb push_back
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
inline ll read() {
ll f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return f * x;
}
void print(ll x) {
if(x < 10) {
putchar(x + 48);
return ;
}
print(x / 10);
putchar(x % 10 + 48);
}
const int N = 1e5 + 10;
ll a[N], b[N];
int n;
ll quick_mult(ll a, ll b, ll mod) {
ll ans = 0;
while(b) {
if(b & 1) ans = (ans + a) % mod;
b >>= 1;
a = (a + a) % mod;
}
return ans;
}
ll ex_gcd(ll a, ll b, ll & x, ll & y) {
if(!b) {
x = 1, y = 0;
return a;
}
ll gcd = ex_gcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
return gcd;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
n = read();
for(int i = 1; i <= n; i++) a[i] = read(), b[i] = read();
ll ans = b[1], M = a[1];
for(int i = 2; i <= n; i++) {
ll A = M, B = a[i], C = ((b[i] - ans) % a[i] + a[i]) % a[i], x, y;
ll gcd = ex_gcd(A, B, x, y);
B /= gcd;
x = quick_mult(x, C / gcd, B);
ll mod = M * B;
ans = (ans + quick_mult(x, M, mod)) % mod;
M = mod;
}
printf("%lld\n", ((ans % M) + M) % M);
return 0;
}