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

link

EXCRT的学习笔记。

其实感觉也没有阮行止说的那么复杂,感觉第二篇题解说得清楚一些,其实就是考虑怎么在求出前 i 个方程通解的基础上扩展出前 i+1 个方程的通解。

假如当前的通解是 \(x=tM+x_0\) ,有结论是 \(M=lcm(b_1,b_2\dots b_{i-1})\) ,这个可以感性理解。t是浮动变量,x0是前i-1个方程的特解,也就是说我们希望的是找到一个 \(x=tM+x_0\) ,满足 \(x\equiv a_i\pmod{b_i}\) 。推柿子:

\[tM+x_0\equiv a_i\pmod{b_i} \]

\[tM+x_0=a_i-kb_i \]

\[tM+b_ik=a_i-x_0 \]

首先用翡蜀定理判断是否有解,即判断 \(a_i-x_0\)\(gcd(M,b_i)\) 的关系。如果有解就直接除掉gcd,然后用扩欧解方程

\[tM'+kb_i'=1 \]

解出来的 \(t_0\) 要做两步处理。首先模上 \(b_i'\) ,然后乘上 \((a_i-x_0)/gcd\) ,这样我们就得到了一个特解 \(t_0\) 。但别忘了我们的 \(x=tM+x_0\) ,所以要更新答案,并且更新 \(M\) 即可。

#include<bits/stdc++.h>
//#define feyn
#define int long long
#define ll __int128
const int N=100010;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

inline int mul(int s1,int s2,int mod){
	return (int)((ll)s1*(ll)s2%(ll)mod);
}
struct node{int x,y,g;};
inline node exgcd(int a,int b){
	if(b==0)return (node){1,0,a};
	node an=exgcd(b,a%b);
	return (node){an.y,an.x-a/b*an.y,an.g};
}

int m,a[N],b[N];

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);
	for(int i=1;i<=m;i++){
		read(b[i]);read(a[i]);
	}
	int M=b[1],x0=a[1];
	for(int i=2;i<=m;i++){
		node an=exgcd(M,b[i]);
		int c=a[i]-x0,bg=b[i]/an.g;
		int x=mul(an.x,c/an.g,bg);
		x0=(x0+x*M);
		M=M*bg;
	}
	printf("%lld",(x0%M+M)%M);
	
	return 0;
}
posted @ 2022-07-13 17:21  Feyn618  阅读(27)  评论(0编辑  收藏  举报