复习
中国剩余定理:
x
≡
a
1
(
m
o
d
m
1
)
x ≡a_1(mod m_1)
x≡a1(modm1)
x
≡
a
2
(
m
o
d
m
2
)
x ≡a_2(mod m_2)
x≡a2(modm2)
x
≡
a
3
(
m
o
d
m
3
)
x ≡a_3(mod m_3)
x≡a3(modm3)
…
x
≡
(
a
n
m
o
d
m
n
)
x ≡(a_nmod m_n)
x≡(anmodmn)
有整数解 x=
∑
n
i
=
1
a
i
M
i
t
i
\sum_{n}^{i=1}a_iM_it_i
∑ni=1aiMiti
证明:因为
M
i
=
m
/
m
i
M_i=m/m_i
Mi=m/mi,是除了
m
i
m_i
mi之外的所有模数的倍数,所以除了第i组和他进行同余的答案都是0。又因为
a
i
M
i
t
i
≡
a
i
(
m
o
d
m
i
)
a_iM_it_i≡a_i(mod m_i)
aiMiti≡ai(modmi)带入
x
=
∑
n
i
=
1
a
i
M
i
t
i
x=\sum_{n}^{i=1}a_iM_it_i
x=∑ni=1aiMiti。成立
中国剩余定理给出了模数两两互质的现行同余方程组的一个特解。方程组的通解可以表示成
x
+
k
m
x+km
x+km。有些题目要求我们求非负解。只需要把x对m取膜就可以了。
例题:
自从曹冲搞定了大象以后,曹操就开始琢磨让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲很不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。
举个例子,假如有 16 头母猪,如果建了 3 个猪圈,剩下 1 头猪就没有地方安家了;如果建造了 5 个猪圈,但是仍然有 1 头猪没有地方去;如果建造了 7 个猪圈,还有 2 头没有地方去。
你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?
输入格式
第一行包含一个整数 n,表示建立猪圈的次数;
接下来 n 行,每行两个整数 ai,bi,表示建立了 ai 个猪圈,有 bi 头猪没有去处。
你可以假定 ai,aj 互质。
输出格式
输出仅包含一个正整数,即为曹冲至少养猪的数目。
数据范围
1
≤
n
≤
10
1≤n≤10
1≤n≤10,
1
≤
b
i
≤
a
i
≤
1000
1≤b_i≤a_i≤1000
1≤bi≤ai≤1000
所
有
a
i
的
乘
积
不
超
过
1
0
18
所有ai的乘积不超过 10^{18}
所有ai的乘积不超过1018
输入样例:
3
3 1
5 1
7 2
输出样例:
16
感觉crt好多都要用龟速乘
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=15;
int a[N],b[N];
int exgcd(int a,int b,int &x,int &y)
{
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
signed main()
{
int n;
cin>>n;
int M=1;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
M*=a[i];
}
int res=0;
for(int i=1;i<=n;i++){
int mi=M/a[i];
int ti,y;
exgcd(mi,a[i],ti,y);
res+=b[i]*mi*ti;
}
cout<<(res%M+M)%M<<endl;
}
拓展中国剩余定理
当我们mod的数不满足互质的时候,就不能用crt了,需要用excrt。具体操作及证明如下:
假设已经求出了钱k-1个方程构成的方程组解x,记
m
=
∏
1
k
−
1
m
i
m=\prod _{1}^{k-1}m_i
m=∏1k−1mi
则我们
x
+
m
∗
i
x+m*i
x+m∗i为一组通解。
现在我们考虑加入第k组方程。求得一个t使得
x
+
t
∗
m
≡
a
k
(
m
o
d
m
k
)
x+t*m≡a_k(modm_k)
x+t∗m≡ak(modmk)化简得到
t
∗
m
≡
a
k
−
x
(
m
o
d
m
k
)
t*m≡a_k-x(modm_k)
t∗m≡ak−x(modmk)这个时候我们就可以用拓展欧几里得来算出我们的答案有没有解,有解的话我们
x
1
=
t
∗
m
+
x
x_1=t*m+x
x1=t∗m+x。所以excrt其实就是一组一组的使用crt来判断并求解。
板子题传送门
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7;
int a[N],b[N],n;\
int mul(int a,int b,int mod)
{
int res=0;
while(b){
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
int exgcd(int a,int b,int &x,int &y)
{
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int excrt()
{
int x,y,k;
int M=b[1],res=a[1];
for(int i=2;i<=n;i++){
int A=M,B=b[i],c=((a[i]-res)%B+B)%B;
int gcd=exgcd(A,B,x,y),bg=B/gcd;
if(c%gcd) return -1;
x=mul(x,c/gcd,bg);
res+=x*M;
M*=bg;
res=(res%M+M)%M;
}
return (res%M+M)%M;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld%lld",b+i,a+i);
}
printf("%lld",excrt());
}