中国剩余定理及其扩展定理 学习笔记

中国剩余定理及其扩展定理 学习笔记

中国剩余定理,又叫孙子定理,最早出现在我国古代著作《孙子算经》中,OI 中常称其为 CRT(China Remainder Theorem)。

问题

CRT 用于求解线性同余方程组问题,且模数互质:

(a1,a2,...,an)=1{xb1 (mod a1)xb2 (mod a2)...xbn (mod an)

x 的最小非负整数解。

CRT

mi=j=1najai,rimi1(modai)

x0=i=1nbimiri

x0 是一个特解,通解形式如下,因为对于每一个 ai 都有 ai|ai

x=x0+ki=1nai

显然地,最小的非负整数解就是 (x0modai+ai)modai

这其实是一个构造性的算法,接下来证明 x0 是方程的解。

证明:i[1,n]xbi(modai)x0 是其一个解。

对于 ji,ai|mj,所以 x0bimiri(modai)

miri1(modai),所以 x0bi(modai).

注意到 rimimodai 意义下的逆元,由于 a 序列互相互质,所以一定存在逆元,但在去掉这个限制的情况下,逆元不存在,无法通过 CRT 求解。

ExCRT

用于解决线性同余方程组模数不互质的情况,ExCRT 其实和 CRT 没什么关系

考虑一个同余方程组:

{xb1 (mod a1)xb2 (mod a2)

如果能把它们两个合并成一个方程,然后迭代地合并所有方程,最后得到一个唯一的同余方程,岂不美哉?

先考虑把方程拿出同余系:

{x=b1+pa1x=b2+qa2b2+qa2=b1+pa1pa1qa2=b2b1

发现这是一个 ExGcd(aka 裴蜀定理)的形式,方程无解当且仅当 gcd(a1,a2)(b2b1),于是可以通过 ExGcd 求出 p,q 的特解,设其为 p0,q0,则 p,q 的通解为:

{p=p0+a2gcd(a1,a2)tq=q0+a1gcd(a1,a2)t

所以把通解代入一开始其中一个方程中得到:

x=b1+p0a1+a1a2gcd(a1,a2)tx=b1+p0a1+lcm(a1,a2)txb1+p0a1(modlcm(a1,a2))

至此,我们将两个同余方程合并为一个同余方程,重复 n1 次合并,最终剩下一个同余方程,这样最小正整数解就呼之欲出了。

C++ 实现

Problem: P4777 【模板】扩展中国剩余定理(EXCRT)

// Problem: P4777 【模板】扩展中国剩余定理(EXCRT)
// Contest: Luogu
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-11-11 13:26:13

#include <algorithm>
#include <iostream>
#define int long long
#define ll __int128
using namespace std;
const int N = 1e5 + 10;

int n, p[N], a[N];
int exgcd(ll a, ll &x, ll b, ll &y) {
    if(!b) return x = 1, y = 0, a;
    ll d = exgcd(b, y, a % b, x);
    return y -= a / b * x, d;
}

int excrt() {
    for(ll i = n - 1, k1, k2, d; i; i --) {
        d = __gcd(p[i], p[i + 1]);
        if((a[i + 1] - a[i]) % d) return -1; // 本题中不存在无解,但是无解情况不要漏
        exgcd(p[i], k1, p[i + 1], k2);
        k1 = k1 * (a[i + 1] - a[i]) / d % (p[i + 1] / d);
        a[i] += k1 * p[i], p[i] = p[i] / __gcd(p[i], p[i + 1]) * p[i + 1], a[i] %= p[i];
    }
    return (a[1] % p[1] + p[1]) % p[1];
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> p[i] >> a[i];
    cout << excrt() << '\n';

    return 0;
}
posted @   MoyouSayuki  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
:name :name
点击右上角即可分享
微信分享提示