CRT exCRT学习笔记

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} xa1(modm1)xa2(modm2).xan(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) Miti1(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 i1 组方程的解 x x x lcm ⁡ j = 1 i − 1 \operatorname{lcm}_{j=1}^{i-1} lcmj=1i1 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×tai(modmi),即 k × t ≡ a i − x ( m o d    m i ) k\times t \equiv a_i-x(\mod m_i) k×taix(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;
} 
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值