中国剩余定理——一分钟从入门到放弃

Description

给定 n n n个限制条件,形如 x x x a i a_i ai等于 b i b_i bi,求 x x x的最小整数解。

例如,三个限制条件为

3 1
5 1
7 2

(每一行第一个数是 a i a_i ai,第二个是 b i b_i bi)

答案为

16

Solution

这是中国剩余定理的板子题。

直接给出结论: 设 m u l = ∏ i = 1 n a i mul=\prod_{i=1}^n a_i mul=i=1nai, m i = m u l a i m_i=\frac {mul} {a_i} mi=aimul, t i t_i ti为在膜 a i a_i ai意义下 m i m_i mi的逆元。

x x x的一个整数解为 ∑ i = 1 n b i t i m i \sum_{i=1}^n b_it_im_i i=1nbitimi

Proving

首先,由于 m i = m u l a i m_i=\frac {mul} {a_i} mi=aimul,所以对于任意 j ≠ i j≠i j=i,有 m i m_i mi a j a_j aj的倍数。

所以,在某一项 b i t i m i b_i t_i m_i bitimi中,由于 m i m_i mi膜其他的 a j a_j aj都是 0 0 0,所以这一项与其他的限制无关。

又因为 t i t_i ti m i m_i mi在膜 a i a_i ai意义下的逆元,所以 m i t i m_i t_i miti a i a_i ai 1 1 1;所以 m i t i b i m_i t_i b_i mitibi a i a_i ai b i b_i bi。即,对于任意一项 b i t i m i b_it_im_i bitimi,我们既满足了这个限制条件,也没有影响别的限制条件的成立。

证 毕 \huge 证毕

Code

模板: 洛谷P1495

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,mul=1,ans=0,x,y;
int a[20005],b[20005],M[20005],t[20005];

inline void exgcd(int a,int b,int &x,int &y)
{
	if (b==0)
	{
		x=1,y=0;
		return;
	}
	exgcd(b,a%b,x,y);
	
	int savex=x;
	x=y;
	y=savex-(a/b)*y;
}

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)  cin>>a[i]>>b[i];
	for (int i=1;i<=n;i++)  mul*=a[i];
	for (int i=1;i<=n;i++)  M[i]=mul/a[i];
	for (int i=1;i<=n;i++)  exgcd(M[i],a[i],x,y),t[i]=(x+2*a[i])%a[i];
	for (int i=1;i<=n;i++)  ans=(ans+M[i]*t[i]*b[i])%mul;
	cout<<ans<<endl;
	
	return 0;
}

注意点

一定要开 l o n g   l o n g long\ long long long。并且用这个东西的时候,千万小心溢出 l o n g   l o n g long\ long long long要仔细观察数据范围
②求逆元的时候,由于 a i a_i ai不一定是质数,所以要用扩欧来求逆元,而不能用费吗小定理(费马小定理满足要求当且仅当模数为质数)。如果 m u l mul mul a i a_i ai不互质咋办?这个就说明模数不两两互质,那么普通的中国剩余定理就不再适用,得用扩展中国剩余定理。
③在膜意义下的逆元可能是负数,所以要再加上一个 a i a_i ai,详见代码倒数第 6 6 6行;
④最终解出的 x x x是一个特解而不是最小整数解,还要膜上 m u l mul mul

时间复杂度 O ( n ) O(n) O(n),这个问题被中国人巧妙解决。但是,最后再强调一遍,如果模数不两两互质,普通中国剩余定理不再适用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值