扩展中国剩余定理

用途和介绍

用于求解线性方程组:
\(\begin{cases}x\equiv a1(\bmod m1) \\x\equiv a2(\bmod m2) \\...... \\x\equiv an(\bmod mn) \end{cases}\)

数学归纳法:设\(x\)为前\(k-1\)个同余方程的一个特解,则通解为\(x+t\times M\),其中\(M=lcm(m[1],m[2],m[3],......,m[k-1])\),那么\(x+t\times M=a[k](\bmod m[k])\),只要有\(k\)存在,那么第\(k\)个方程亦有解。

观察这个式子,把\(x\)移项,使用扩展欧几里得算法,不要忘记裴蜀定理判无解。

扩展中国剩余定理的优势在于消除了中国剩余定理\(m1,m2,...,mn\)互质的要求。

一些例子

P4777 【模板】扩展中国剩余定理(EXCRT)

板子,代码里的所有有关数组名称都和上文一样

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=100010;
int x,y,n;
int a[N],m[N];

int exgcd(int a,int b){
	if(b==0){
		x=1,y=0;
		return a;
	}
	else{
		int as=exgcd(b,a%b);
		int xx=x,yy=y;
		x=yy,y=xx-(a/b)*yy;
		return as;
	}
}

int qmul(int af,int bf,int p){
	int aa=0,x=af;
	//cout<<"yes"<<endl;
	while(bf){
		if(bf&1){
			aa+=x;
			aa%=p;
		}
		x*=2;
		x%=p;
		bf/=2;
	}
	//cout<<"ok"<<endl;
	return aa;
}

void excrt(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>m[i]>>a[i];
	}
	int ans=a[1],lcm=m[1];
	for(int i=2;i<=n;i++){
		int aa=lcm,bb=m[i],cc=a[i]-ans;
		cc=(cc%m[i]+m[i])%m[i];
		int d=exgcd(aa,bb);
		if(cc%d){
			return;//这题保证一定有解,这一行是裴蜀定理判无解
		}
		ans=ans+lcm*qmul(x,cc/d,m[i]);//qmul是龟速乘,直接乘会爆
		lcm/=d,lcm*=m[i];
		ans=(ans%lcm+lcm)%lcm;
	}
	cout<<ans;
}

signed main(){
	excrt();
	return 0;
}

CF687B Remainders Game

其实是结论题,如果我们知道一个数\(x\)除以\(c_1,c_2,...,c_n\)的余数,相当于是给了一个线性同余方程组。

通过扩展中国剩余定理可以解出一个特解\(x'\),那么\(x=x'+lcm(c_1,c_2,...,c_n)\),相当于可以得到任意数除以\(lcm(c_1,c_2,...,c_n)\)的余数。

如果\(k\)是这个\(lcm\)的因数就可以得到任意数除以\(k\)的余数,否则不行。

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	int n,k;
	cin>>n>>k;
	int p=1;
	for(int i=1;i<=n;i++){
		int c;
		cin>>c;
		p=(p*c)/__gcd(p,c);
		p%=k;
	}
	if(p%k==0) cout<<"Yes";
	else cout<<"No";
	return 0;
}

P2480 [SDOI2010] 古代猪文

一道大综合题。

首先写出题目要求的式子:\(g^{\sum_{d|n}C_{n}^{d}}\)\(\bmod 999911659\)

次数太高,自然想到欧拉定理降次数,由欧拉定理:\(a^b\equiv a^{b\bmod \varphi (p)}(\bmod p)\)

由于\(999911659\)是质数,有\(\varphi(999911659)=999911658\),那么只要求\(g^{\sum_{d|n}C_{n}^{d}\bmod 999911658}\)\(\bmod 999911659\)

计算瓶颈在于\(\sum_{d|n}C_{n}^{d}\bmod 999911658\),首先分解质因数。然后发现\(n\)很大,不好处理组合数的除法,那么使用卢卡斯定理。

卢卡斯定理:
\(p\)为质数,有:

\[C_{n}^{m}\bmod p= C_{n\bmod p}^{m\bmod p}\times C_{n/p}^{m/p}\bmod p \]

但是,\(999911658\)并不是质数,只能先把它质因数分解,发现只分解出\(4\)个质因子,\(999911658=2\times 3\times 4679\times 35617\)

如果我们知道\(C_{n}^{d}\)分别除以这四个质因数的值,相当于是知道了四个同余式,那么这就是一个把\(C_{n}^{d}\)看成未知数解出这个线性同余方程组即可。

当然因为线性同余方程组里的余数都是质数,使用中国剩余定理也可以(调不出来了代码换成了中国剩余定理)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=100010;
int x,y,n,p,g;
int a[N],m[5]={0,2,3,4679,35617};
int pre[N];

void prev(){
	pre[0]=1;
	for(int i=1;i<=100000;i++){
		pre[i]=(pre[i-1]*i);
		pre[i]%=p;
	}
}

int qpow(int aa,int bb){
	int vl=1,hl=aa;
	hl%=p;
	while(bb){
		if(bb%2){
			vl*=hl;
			vl%=p;
		}
		hl*=hl;
		hl%=p;
		bb/=2;
	}
	return vl;
}

int C(int aa,int bb){
	if(aa<bb) return 0;
	int ans=pre[aa];
	ans*=qpow(pre[aa-bb],p-2);
	ans%=p;
	ans*=qpow(pre[bb],p-2);
	ans%=p;
	return ans;
}

int lucas(int aa,int bb){
	if(bb==0) return 1;
	int val=C(aa%p,bb%p);
	val*=lucas(aa/p,bb/p);
	val%=p;
	return val;
}

int exgcd(int a,int b){
	if(b==0){
		x=1,y=0;
		return a;
	}
	else{
		int as=exgcd(b,a%b);
		int xx=x,yy=y;
		x=yy,y=xx-(a/b)*yy;
		return as;
	}
}

int add(int pla){
	//cout<<n<<" "<<pla<<" "<<p<<" "<<C(n,pla)<<" "<<lucas(n,pla)<<"\n";
	return lucas(n,pla)%p;
}

void excrt(){
	cin>>n>>g;
	for(int i=1;i<=4;i++){
		p=m[i];
		prev();
		for(int j=1;j*j<=n;j++){
			if(!(n%j)){
				//cout<<"in"<<"\n";
				a[i]+=add(j);
				a[i]%=p;
				if((n/j)==j) continue;
				a[i]+=add(n/j);
				a[i]%=p;
			}
		}
		//cout<<a[i]<<" "<<m[i]<<"\n";
	}
	int ans=0;
	for(int i=1;i<=4;i++){
		p=m[i];
		ans=(ans+a[i]*(999911658/m[i])%999911658*qpow(999911658/m[i],m[i]-2));
	}
	p=999911659;
	if(g%p==0){
		cout<<0;
		return;
	}
	cout<<qpow(g,ans);
}

signed main(){
	excrt();
	return 0;
}

P4774 [NOI2018] 屠龙勇士

其实是典题,但是和数组结构结合了一下还是有训练价值的。

使用平衡树(好像可以用\(multiset\))找出每一轮使用的剑(支持插入,删除,找前驱,最小值),然后就是扩展中国剩余定理的板子。

还未更新完。

posted @ 2024-11-03 16:16  星河倒注  阅读(9)  评论(0编辑  收藏  举报