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
#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),这个问题被中国人巧妙解决。但是,最后再强调一遍,如果模数不两两互质,普通中国剩余定理不再适用。