中国剩余定理

中国剩余定理

引子:曹冲养猪

题目链接:https://www.luogu.com.cn/problem/P1495
自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。举个例子,假如有 1616 头母猪,如果建了 33 个猪圈,剩下 11 头猪就没有地方安家了。如果建造了 55 个猪圈,但是仍然有 11 头猪没有地方去,然后如果建造了 77 个猪圈,还有 22 头没有地方去。你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?

类似此类问题我们可以使用中国剩余定理求解
限制条件模两两互质

推导

推导过程来源于百度百科(主要是太菜了不会推导)

求解模板

以如下问题为例
问:有数模3余2,模5余3,模7余2,问数几何?

  • 衍数:lcm/除数
  • 逆元:为衍数模除数意义下的数论倒数,设衍数为a,除数为b,则逆元为ax ≡ 1(mod b)的最小正整数解
  • 各总:余数 * 衍数 * 逆元
除数 余数 除数最小公倍数(lcm) 衍数 逆元 各总
3 2 105 35 2 140
5 3 105 21 1 63
7 2 105 15 1 30

将"各总"相加得到特解233
最后将233对lcm取模得到最小正整数解23
23即为所求

代码实现

void exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1,y=0;
		return ;
	}
	exgcd(b,a%b,y,x);
	y-=(a/b)*x;
}
void init(){
	x=0,y=0;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++) m[i]=read(),ai[i]=read();
	ll M=1;
	for(int i=1;i<=n;i++) M*=(ll)m[i];//求lcm 
	for(int i=1;i<=n;i++) mi[i]=M/m[i];//求衍数 
	//求逆元
	for(int i=1;i<=n;i++){exgcd(mi[i],m[i],x,y);ti[i]=(x%m[i]+m[i])%m[i];init();}
	ll minx=0;
	for(int i=1;i<=n;i++) minx+=(mi[i]*ai[i]*ti[i])%M;
	printf("%lld",minx%M);
	return 0;
}
posted @ 2022-06-06 17:22  ThinkGone  阅读(41)  评论(0编辑  收藏  举报