ExCRT

\[\begin{cases} x\equiv a_1\pmod{m_1}\\ x\equiv a_2\pmod{m_2}\\ \vdots\\ x\equiv a_n\pmod{m_n} \end{cases} \]

的一个任意解。

以上是 ExCRT解决的问题。
https://www.luogu.com.cn/problem/P4777


  1. 递归:利用 exgcd 合并 i-1,i 方程
  2. 最后剩下的方程的 \(a_n\) 稍加取模得到答案

如何使用 exgcd 合并方程

\[\begin{cases} x\equiv a_1\pmod{m_1}\\ x\equiv a_2\pmod{m_2} \end{cases},\\ x=k_1m_1+a_1=k_2m_2+a_2,\\ m_1k_1-m_2k_2=a_2-a_1. \]

显然使用 exgcd 求解↑。
\(k_1/k_2\) 回带得 \(x\) 的一个任意解。
不难发现通解 \(x\equiv x^*\pmod {\operatorname{lcm}(m_1,m_2)}\)\(x^*\) 代表特解)。

注意事项

  1. 龟速乘——可能1e18*1e18
  2. 及时取模——模数不同,不能留负数
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n;
pair<int,int>a[N];
int exgcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return a;}
	int d=exgcd(b,a%b,x,y),x1=x,y1=y;
	x=y1,y=x1-a/b*y1;
	return d;
}
int mul(int a,int b,int mod){
	int c=0;
	while(b){
		if(b%2)c=(c+a)%mod;
		a=(a+a)%mod,b/=2;
	}
	return (c+mod)%mod;
}
pair<int,int>work(pair<int,int>a,pair<int,int>b){
	pair<int,int>c;
	int x,y,A=a.second,B=-b.second,C=b.first-a.first,d=exgcd(A,B,x,y),l=abs(a.second/d*b.second);
	if(C%d)return make_pair(-1,-1);
	C/=d,x=mul(C,x,l);
	return make_pair(((mul(a.second,x,l)+a.first)%l+l)%l,l);
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i].second>>a[i].first;
	for(int i=2;i<=n;i++)a[i]=work(a[i-1],a[i]);
	cout<<(a[n].first?a[n].first:a[n].second);
}
posted @ 2022-02-06 22:26  pengyule  阅读(114)  评论(0)    收藏  举报