CRT
中国剩余定理用于求解这样一组同余式的最小正整数解:
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) … . … x ≡ a n ( m o d m n ) \begin{cases}x\equiv a_1(\mod m_1)\\x\equiv a_2(\mod m_2)\\… .…\\x\equiv a_n(\mod m_n)\end{cases} ⎩ ⎨ ⎧x≡a1(modm1)x≡a2(modm2)….…x≡an(modmn)
其中 a 1 , a 2 , … … a n a_1,a_2,……a_n a1,a2,……an 两两互质。
设
M
=
∏
i
=
1
n
M=\prod_{i=1}^n
M=∏i=1n
m
i
m_i
mi,
M
i
=
M
÷
m
i
M_i=M\div m_i
Mi=M÷mi (原谅我的变量重名但只有这样看着顺眼qwq
构造逆元 t i t_i ti 使得 M i t i ≡ 1 ( m o d m i ) M_i t_i\equiv 1(\mod m_i) Miti≡1(modmi),那么当前方程显然就有解 M i t i a i M_it_ia_i Mitiai,所以方程组就有解 x = ∑ i = 1 n x=\sum_{i=1}^n x=∑i=1n M i t i a i M_it_ia_i Mitiai,这是由于 M i M_i Mi 的存在使得第 i i i 个方程的解对其余方程均无影响,所以加起来一定正确。
能求出一个解,则其它解均为 x + k × M x+k\times M x+k×M的形式,最小正整数解就也可求了。
代码实现的话, t i t_i ti 用扩展欧几里得求解,注意乘法可能爆long long,要龟速乘就好了。
#include<bits/stdc++.h>
#define int long long
#define ff(i,s,e) for(int i=(s);i<=(e);++i)
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=15;
int n,a[N],b[N],m[N];
inline void exgcd(int a,int b,int &x,int &y){
if(!b) return x=1,y=0,void();
exgcd(b,a%b,x,y);
int t=x;
x=y,y=t-a/b*y;
}
inline int mul(int x,int y,int mod){
int res=0;
for(;y;y>>=1){
if(y&1) res=(res+x)%mod;
x=(x<<1)%mod;
}
return res;
}
signed main(){
n=read();
int M=1;
ff(i,1,n) a[i]=read(),b[i]=read(),M*=a[i];
ff(i,1,n) m[i]=M/a[i];
int ans=0;
ff(i,1,n){
int x,y;
exgcd(m[i],a[i],x,y);
x=(x%M+M)%M;
ans=(ans%M+mul(m[i],mul(x,b[i],M),M)+M)%M;
}
printf("%lld",ans);
}
exCRT
中国剩余定理的求解基于求逆元,而当任意两个 m i m_i mi 不互质的时候, M i M_i Mi 在 m i m_i mi 的剩余系下的逆元不存在,所以 m i m_i mi 不两两互质的情况下无法用普通CRT求解。
于是考虑另一种思路:假设已经求出前 i − 1 i-1 i−1 组方程的解 x x x, lcm j = 1 i − 1 \operatorname{lcm}_{j=1}^{i-1} lcmj=1i−1 m i = t m_i=t mi=t,则通解为 x + k × t x+k\times t x+k×t,那么加入第 i i i 个方程就是要求解 k k k 使得 x + k × t ≡ a i ( m o d m i ) x+k\times t \equiv a_i(\mod m_i) x+k×t≡ai(modmi),即 k × t ≡ a i − x ( m o d m i ) k\times t \equiv a_i-x(\mod m_i) k×t≡ai−x(modmi),扩欧求解即可,若有任意一个同余式无解,则整个方程组无解。
一定要注意好当前是在谁的剩余系里啊/kk
#include<bits/stdc++.h>
#define int long long
#define ff(i,s,e) for(int i=(s);i<=(e);++i)
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e5+5;
int n,a[N],b[N];
inline int lcm(int x,int y){
return x/__gcd(x,y)*y;
}
inline void exgcd(int a,int b,int &x,int &y){
if(!b) return x=1,y=0,void();
exgcd(b,a%b,x,y);
int t=x;
x=y,y=t-a/b*y;
}
inline int mul(int x,int y,int mod){
int res=0;
for(;y;y>>=1){
if(y&1) res=(res+x)%mod;
x=(x+x)%mod;
}
return res;
}
signed main(){
n=read();
ff(i,1,n) a[i]=read(),b[i]=read();
int ans=b[1],m=a[1];
ff(i,2,n){
int x,y;
int g=__gcd(m,a[i]),c=(b[i]+a[i]-ans%a[i])%a[i];
exgcd(m,a[i],x,y);
x=mul(x,c/g,a[i]/g);
ans+=x*m;
m*=a[i]/g;
ans=(ans%m+m)%m;
}
printf("%lld",ans);
return 0;
}