中国剩余定理及其拓展

中国剩余定理

实质就是解 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] 时余数, a [ i ] a[i] 是模数。

显然对于一个方程我们可以直接得到 a n s 1 = b [ 1 ] ans_1 = b[1] ,用这个答案去求解第二个方程,解显然可以描述为 a n s 2 = a n s 1 + k a [ 1 ] ans_2 = ans_1 + 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]}

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 k 就行,无非就是做一次 e x g c d exgcd 嘛,得到

a n s 2 = a n s 1 + k a [ 1 ] ans_2 = ans_1 + 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} ,也就是把上面推导的式子换成前 k 1 k - 1 项的 l c m 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;
}

猜你喜欢

转载自blog.csdn.net/weixin_45483201/article/details/107623117