扩展中国剩余定理 EXCRT

扩展中国剩余定理 EXCRT

题目描述

给定 n n n个同余式, m 1 , m 2 . . . , m n m_1,m_2...,m_n m1,m2...,mn不一定互质
内容
问,满足上述同余式最小的 x x x是多少

解决方法

显然不能再用CRT的方法来求解了
那么我们考虑逐一进行求解
假设当前已经求出前 k − 1 k-1 k1个方程组的解,记为 x x x
且有 M = ∏ i = 1 k − 1 m i M=\prod_{i=1}^{k-1}m_i M=i=1k1mi
那么前k-1个方程组的同解即为 x + i ∗ M , i ∈ Z x+i*M,i\in Z x+iM,iZ

那么对于当前加入的第 k k k个方程组,我们其实就是需要找到一个 t t t,使得 x + t ∗ M ≡ a k ( m o d m k ) x+t*M\equiv a_k\pmod{m_k} x+tMak(modmk)
稍微转化一下这个式子 ⇒ t ∗ M ≡ a k − x ( m o d m k ) \Rightarrow t*M\equiv{a_k-x}\pmod{m_k} tMakx(modmk)
那么就可以用拓欧来解决这个式子了,如果该方程无解,那么整个方程组无解,否则继续解下去

可以发现EXCRT的本质就是求解n次拓展欧几里得

例题 P4777-板子

代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f; 
}
int k,a[100009],b[100009];
int ksm(int a,int b,int mod){
	int ans=1;
	while(b){
		if(b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}return ans;
}
int qmul(int a,int b,int mod){
	int ans=0;
	while(b){
		if(b&1) ans=(ans+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}return ans;
}
int exgcd(int a,int b,int &x,int &y){
	if(b==0){x=1,y=0;return a;}
	int d=exgcd(b,a%b,x,y);
	int tmp=x;
	x=y,y=tmp-a/b*y;
	return d;
}
int excrt(){
	int ans=b[1],lcm=a[1],x,y;
	for(int i=2;i<=k;i++){
		int c=(b[i]-ans%a[i]+a[i])%a[i];
		int d=exgcd(lcm,a[i],x,y);
		if(c%d) return -1;
		int r=a[i]/d;
		x=qmul(x,c/d,r);
		ans+=x*lcm;
		lcm*=r;
		ans=(ans%lcm+lcm)%lcm;
	}return ans=(ans%lcm+lcm)%lcm;
}
signed main(){
	k=read();
	for(int i=1;i<=k;i++) a[i]=read(),b[i]=read();
	printf("%lld\n",excrt());
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值