专栏文章

P4777题解

P4777题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@mion9pvh
此快照首次捕获于
2025/12/02 21:59
3 个月前
此快照最后确认于
2025/12/02 21:59
3 个月前
查看原文

P4777 题解

2025.8.21 更正一处笔误。

题目链接

题意解释

给定 nn 组非负整数 ai,bia_i,b_i,求解关于 xx 的方程组的最小非负整数解:
{xb1(moda1)xb2(moda2)xbn(modan)\begin{cases}x\equiv b_1\pmod{a_1}\\x\equiv b_2\pmod{a_2}\\\dots\\x\equiv b_n\pmod{a_n}\end{cases}

数学前置知识

解方程:{xb1(moda1)xb2(moda2)xbn(modan)\begin{cases}x\equiv b_1\pmod{a_1}\\x\equiv b_2\pmod{a_2}\\\dots\\x\equiv b_n\pmod{a_n} \end{cases}
其中 a1,a2,,ana_1,a_2,\dots,a_n 两两互质。
我们可以构造 M=i=1naiM=\prod_{i=1}^{n}{a_i} 并令 Mk=MakM_k=\frac{M}{a_k}yky_kMkM_k 在模 aka_k 意义下的逆元。
此时方程的解 x=i=1naiMiyix = \sum_{i=1}^{n}{a_i M_i y_i}
这便是中国剩余定理(CRT)

但中国剩余定理有一个条件:要求 a1,a2,,ana_1,a_2,\dots,a_n 两两互质。
这也没有关系,我们可以任取 {xbi(modai)xbj(modaj)\begin{cases}x\equiv b_i\pmod{a_i}\\x\equiv b_j\pmod{a_j}\end{cases} 并计算出特解 x0x_0,此时就会有通解 x=x0klcm(ai,aj)x=x_0-k \operatorname{lcm}(a_i,a_j),也就是说这两个方程会合并成一个方程 xx0(modlcm(ai,aj))x\equiv x_0 \pmod{\operatorname{lcm}(a_i,a_j)},这便是扩展中国剩余定理的核心思想。

证明

{xbi(modai)xbj(modaj)\begin{cases}x\equiv b_i\pmod{a_i}\\x\equiv b_j\pmod{a_j}\end{cases}
转化成一般形式 {k1ai+bi=xk2aj+bj=x\begin{cases}k_1 a_i+b_i=x\\k_2 a_j+b_j=x\end{cases}
移项得 k1aik2aj=bjbik_1 a_i-k_2 a_j=b_j-b_i
此时我们已知 ai,aj,bi,bja_i,a_j,b_i,b_j,但未知 k1,k2k_1,k_2
将其看作关于 k1,k2k_1,k_2 的不定方程,根据裴蜀定理,若 gcd(ai,aj)(bibj)\gcd(a_i,a_j)\nmid(b_i-b_j),则方程无解。
对于有解的情况,用扩展欧几里得算法求出特解,并推出通解:
g=gcd(ai,aj),d1=aig,d2=ajgg=\gcd(a_i,a_j),d_1=\dfrac{a_i}{g},d_2=\dfrac{a_j}{g}
代入原方程得:
k1d1gk2d2g=bjbik_1 d_1 g-k_2 d_2 g=b_j-b_i
g0k1d1k2d2=bjbigk1d1k2d2Zg(bjbi)\because g\ne0\\\therefore k_1 d_1-k_2 d_2=\frac{b_j-b_i}{g}\\\because k_1 d_1-k_2 d_2\in\mathbb{Z}\\\therefore g\mid(b_j-b_i)
设特解为 ω1,ω2\omega_1,\omega_2,则 k1,k2k_1,k_2 的特解为:
{k1=bjbigω1k2=bjbigω2\begin{cases}k_1=\dfrac{b_j-b_i}{g}\omega_1\\k_2=-\dfrac{b_j-b_i}{g} \omega_2 \end{cases}
求得特解 x0=k1ai+bi=bjbigω1+bix_0 = k_1 a_i+b_i=\dfrac{b_j-b_i}{g} \omega_1+b_i
原方程通解为 x=x0klcm(ai,aj),kZx=x_0-k\operatorname{lcm}(a_i,a_j),k\in \mathbb{Z}
证毕。

算法流程

  1. 初始化等价方程 x0(mod1)x \equiv 0\pmod{1}(即 A=1,B=0A=1, B=0
  2. 依次合并每个方程 xbi(modai)x \equiv b_i\pmod{a_i}
    • 计算 g=gcd(A,ai)g = \gcd(A,a_i)
    • 用扩展欧几里得算法解 Ax+aiy=gA\cdot x+a_i\cdot y=g
    • g(Bbi)g\nmid(B-b_i),则无解。
    • 计算特解 x0=BAxBbigx_0=B-A\cdot x\cdot\dfrac{B-b_i}{g}
    • 更新模数 A=AaigA=\dfrac{A\cdot a_i}{g}
    • 更新余数 B=x0modAB=x_0\bmod A
  3. 最终解为 BmodAB\bmod A(取最小非负整数)。

AC 代码

CPP
#include<bits/stdc++.h>
#define ll __int128 //数据量过大long long也不会溢出
using namespace std;
const int N=1e5+5,M=1e5+5;
int n;
ll A=1,B=0,x,y;
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	else{
		ll aa=exgcd(b,a%b,y,x);
		y-=a/b*x;
		return aa;
	}
}//扩展欧几里得算法
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
    	long long a,b;
		cin>>a>>b;
		ll gd=exgcd(A,a,x,y);
		x=(B-b)/gd*x;
		B=B-A*x;
		A=a/gd*A;
		B=(B%A+A)%A;
	}
	long long ans=(B%A+A)%A;
	cout<<ans<<"\n";
	return 0;
}

评论

3 条评论,欢迎与作者交流。

正在加载评论...