excrt

摘自蓝书

考虑使用数学归纳法,假设已经求出了前 \(k-1\) 个方程构成的方程组的一个解 \(x\)。记 \(m= lcm (m_1,m_2,...,m_{k-1})\),则 \(x+i*m(i\in Z)\) 是前面方程组的一个通解。

简单证明下。

\[x\equiv a_i \pmod{m_i} \]

因为有

\[m_i|m \]

所以

\[x+i*m\equiv a_i \pmod{m_i} \]

考虑第 \(k\) 个方程,求出一个整数 \(t\),使得 \(x+t*m\equiv a_k \pmod{m_k}\)。exgcd 直接做就好了,注意要求出 \(x\) 的最小解(https://www.luogu.com.cn/blog/McHf/p5656-exgcd)

#include <bits/stdc++.h>
#define int __int128 
#define pb push_back
using namespace std;
int rd() {
	int f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
void pr(int x) {
	if(x<0) {putchar('-');x=-x;}
	if(x>9) pr(x/10);
	putchar(x%10+'0');
}
const int N=(int)(1e5+5);
int A[N],m[N],n,x,y;

void exgcd(int a,int b) {
	if(!b) {
		x=1; y=0; return ;
	}
	exgcd(b,a%b);
	int x1=0,y1=0;
	x1=y; y1=x-(a/b)*y;
	x=x1; y=y1;
}

inline int lcm(int x,int y) {
	return x/__gcd(x,y)*y;
}

signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	n=rd();
	for(int i=1;i<=n;i++) m[i]=rd(),A[i]=rd();
	int ans=A[1],M=m[1];
	bool fl=1;
	for(int i=2;i<=n;i++) {
		int a=M,b=m[i],C=(A[i]-ans%b+b)%b;
		int d=__gcd(a,b);
		if(C%d) {
			fl=0; break ;
		}
		exgcd(M,m[i]);
		x=x*(C/d)%(m[i]/d);
		ans+=x*M; M=lcm(M,b);
		ans=(ans%M+M)%M;
	}
	pr((ans%M+M)%M);
	return 0;
}
posted @ 2022-07-07 15:45  FxorG  阅读(54)  评论(0编辑  收藏  举报