论扩展中国剩余定理(EXCRT)(洛谷P4777模板题)

论扩展中国剩余定理---EXCRT---洛谷P4777模板题

1前言

之前挖了个大坑,EXCRT,紫题啊,本蒟蒻不会
拖了很长时间,终于来填这个坑
前置知识:EXGCD,CRT(其实没啥关系 ,但是要知道CRT为什么不行),建议阅读我之前的博客

2问题

给定n个整数ai,mi(mi之间不一定互质)–>(不一定互质,就是和CRT的区别)
使得存在一个整数x满足
x mod m1 = a1
x mod m2 = a2

x mod mn = an

即给定x除以n个整数的余数
求最小的x

3告别CRT

CRT是将Mi乘以它对mi的乘法逆元,得到mod mi为1,再乘以ai,mod mi为ai,且mod mj(j不等于i)为0
把所有得数相加,得出解
但是,问题来了,如果mi能整除Mi呢?
0没有倒数,模数为0没有逆元!

CRT无了,如果每个mi不互质,就会出现上面情况
而且构造模数为1还是CRT最主要的思想,根本没法改
这就要请出EXCRT了

4EXCRT

举个例子
x≡2(mod4)
x≡4(mod6)
先看看能不能找到规律
满足第一个方程的数:2,6,10,14,18,22,26,30,34,38,42,46,50…
满足第二个方程的数:4,10,16,22,28,34,40,46…
可见方程组在50以内的解10,22,34,46
发现规律了吗,等差数列,这是同余方程解的性质
CRT最后也是通过模M来得到最小整数解
可以看到,方程合并了,上面两个方程可合并为
x≡10(mod12)
要是一直合并,最后只剩一组,不就好办了吗
合并一组找不到规律,再来两组
(1)
x≡4(mod6)
x≡3(mod5)
在100以内的解28,58,88
合并为x≡28(mod30)
模数的规律找到了,为两个模数的最小公倍数,这点和CRT一样
但是余数好像没什么规律…继续看看
(2)
x≡2(mod4)
x≡3(mod6)
这个无解
为什么
满足第一个方程必为偶数,有如下解:2,6,10,14,18,22,26,30,34,38,42,46,50…
满足第二个方程必为奇数,有如下解:3,9,15,21,27,33,39,45…
可是CRT一定有解
把6换成5,这就有解
互质和不互质区别就在gcd
我尝试枚举,把第二个方程的余数改成0-5的每一个整数
发现,当模数为0,2,4的时候,有解
这个性质很妙,但是不能得出一般性规律
设有如下方程
x≡a1(mod m1)
x≡a2(mod m2)
要求x,先把x表示一下
x = k1m1+a1 = k2m2+a2
则k1m1-k2m2 = a2-a1
这是…裴蜀定理!
所以,当gcd(m1,m2)可以整除(a2-a1)是,就有一组k1,k2使方程有解,进而求出x
那么,怎么求?
可以看到m1,m2,a1,a2均为已知数,设d = gcd(m1,m2),p1 = m1/d,p2 = m2/d,都除以最大公约数了,p1p2显然互质
那么,在有解的基础上,可以这样求k1k2
k1p1-k2p2 = (a2-a1)/d
我们单看方程左侧,p1p2互质,可以再用裴蜀定理
列出方程
y1p1-y2p2 = 1
这个还解不了
先改为y1*p1+(-y2)*p2 = 1
这个是一般式,放进exgcd求解,最后把求的解变为相反数,即得y2
现在回归k1,k2
设(a2-a1)/d = h,两个方程比对
第二个方程乘以h即可得到第一个方程
那么k1 = y1h,k2 = y2h
再带回一次,x = y1hm1+a1,求出x
因为等差数列性质,x只要摸上lcm(m1,m2),即m1m2的最小公倍数,即可求出新方程的余数,完成合并
并且求出的余数还是方程的最小非负整数解,最后全合并完直接输出
至此,EXCRT完成,附代码(c++)

#include<bits/stdc++.h>
using namespace std;
typedef __int128 ll;
ll x,y,d;
int n;
ll gcd(ll a,ll b){
	if(b==0){
		return a;
	}else{
		return gcd(b,a%b);
	}
}
void exgcd(ll &x,ll &y,ll a,ll b){
	if(b==0){
		d = a;
		x = 1;
		y = 0;
	}else{
		exgcd(y,x,b,a%b);
		y-=a/b*x;
	}
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
ll a,b,a1,b1;
void excrt(){
	exgcd(x,y,a,a1);
	ll c = b1-b;
	x = x*c/d%(a1/d);
	if(x<0)x+=a1/d;
	ll mod = lcm(a,a1);//模数,余数为x 
	b = (a*x+b)%mod;
	if(b<0){//合并方程 
		b+=mod;
	}
	a = mod;
}
int main(){
	cin>>n;
	for(int i = 1;i<=n;i++){
		long long A,B;
		cin>>A>>B;
		a1 = A;
		b1 = B;
		if(i>1){//保证有两个可合并方程 
			excrt();
		}else{
			a = a1;
			b = b1;
		}
	}
	printf("%lld",(long long)(b%a));
	return 0;
}

5后记

作者认为,EXCRT就是n个EXGCD模板(参考洛谷P5656)
这就体现了分治思想,把两个方程提出来,其实不难搞,最巧妙的还是合并方程的思想
本题为蒟蒻的第一道紫题,如有错误欢迎各位神犇指点
森林古猿出品,必属精品,请认准优快云森林古猿1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值