首页 > 其他分享 >扩展中国剩余定理

扩展中国剩余定理

时间:2024-11-03 16:09:14浏览次数:4  
标签:剩余 int 定理 扩展 long times bmod

用途和介绍

用于求解线性方程组:
\(\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\))找出每一轮使用的剑(支持插入,删除,找前驱,最小值),然后就是扩展中国剩余定理的板子。

还未更新完。

标签:剩余,int,定理,扩展,long,times,bmod
From: https://www.cnblogs.com/wangwenhan/p/18522507

相关文章

  • 卢卡斯定理
    公式若n,m为整数,p为质数\[C_{n}^{m}\bmodp=C_{n\bmodp}^{m\bmodp}\timesC_{n/p}^{m/p}\bmodp\]这个式子有什么作用呢,最简单的一种就是求组合数。有时候n,m过大,可能是p的倍数,这时候n,m对于p没有逆元,自然没办法用费马小定理求逆元。这个时候我们就需要卢卡斯定理了求组合......
  • Icaros 3.3.3 测试版 2 是一组轻量级、高质量的 Windows Shell 扩展,能够为几乎任何视
    Suggested useful videotoolsforFREEIcaros3.3.3beta2 isacollectionoflightweight,highquality,WindowsShellExtensions,whichiscapableofprovidingWindowsExplorerthumbnailsforessentiallyanyvideomediafiletype.IcaroscanprovideWindows......
  • H7-TOOL的LUA小程序教程第17期:扩展驱动AD7606, ADS1256,MCP3421, 8路继电器和5路DS18B2
    LUA脚本的好处是用户可以根据自己注册的一批API(当前TOOL已经提供了几百个函数供大家使用),实现各种小程序,不再限制Flash里面已经下载的程序,就跟手机安装APP差不多,所以在H7-TOOL里面被广泛使用,支持在线调试运行,支持离线运行。TOOL的LUA教程争取做到大家可以无痛调用各种功能函数,不需......
  • 探索 cola 扩展组件的应用
    一、痛点在日常开发中,不想通过写一堆if...else...实现业务逻辑判断,使得代码越来越长难以维护,又不想每次都用编码形式在Spring中实现策略模式。要是有一个组件能通过注解配置,同时还能支持多个维度的策略判断就简单了。二、如何解决在学习cola框架时,发现cola扩展组件能通过......
  • 如何过滤出特定扩展名的文件
    在C#中,DirectoryInfo类的GetFiles方法本身并不直接支持通过参数来过滤多种类型的文件。不过,你可以通过组合多个过滤条件来实现这一功能。例如,你可以首先获取所有文件,然后使用LINQ(LanguageIntegratedQuery)来过滤出你需要的文件类型。以下是一个示例,展示了如何过滤出特定扩展名......
  • Chromium 中chrome.topSites扩展接口定义c++
    一、chrome.topSites使用 chrome.topSites API访问新标签页上显示的热门网站(即最常访问的网站)。不包括用户自定义的快捷方式。权限topSites您必须声明“topSites”扩展程序清单中授予使用此API的权限。{ "name":"Myextension", ... "permissions":[ ......
  • 一个简单的 ASP.NET Core 依赖注入例子,提高代码的可维护性和可扩展性
    前言:什么是依赖注入依赖注入可以提高代码的可维护性、可测试性、可替换性和可扩展性,降低组件之间的耦合度,使得代码更加清晰和灵活,ASP.NETCore提供了内置的依赖注入容器,可以帮助我们轻松地将服务注册到容器中。本文主要通过一个简单的例子来阐述ASP.NETCore依赖注入的使用......
  • 使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
    本人之前对C#开发非常喜欢,也从事开发C#开发桌面开发、Web后端、Vue前端应用开发多年,最近一直在研究使用Python,希望能够把C#的一些好的设计模式、开发便利经验引入到Python开发中,很多时候类似的开发方式,可以极大提高我们开发的效率,本篇随笔对wxpython控件实现类似C#扩展函数处理的......
  • 常用极限定理
    1.数列运算法则假设\(lim_{x\to\infty}x_n=a\),\(lim_{y\to\infty}y_n=b\)(1)\(lim_{n\to\infty}(x_n+y_n)=lim_{n\to\infty}x_n+lim_{n\to\inftyy_n}=a+b\)(减法,乘法同)(2)\(lim_{n\to\infty}\frac{x_n}{y_n}=\frac{lim_{n\to\infty}x_......
  • 【时间序列分析】平稳时间序列分析——Wold分解定理和延迟算子
    Wold分解定理(这个定理是平稳时间序列分析的理论基石。)对于任意一个离散平稳时间序列,它都可以分解为两个不相关的平稳序列之和,其中一个为确定性的(deterministic),另一个为随机性的(stochastic) xₜ=Vₜ+ξₜ,{V₁}为确定性平稳序列,ξ₁为随机性平稳序列式中:确定性......