孙子
Preface
数论学习Part 7。
每天进步一点点,退役不会太丢脸。
联赛只剩十五天,隔靴搔痒智何添?
剩余定理四天一篇,动归图论又几何,数据结构似云烟。
莫再等闲,莫忘时间。
CRT
我们小时候都做过这种问题,一个数 x x x它满足 x ≡ { a 1 m o d p 1 a 2 m o d p 2 ⋮ a n m o d p n x\equiv \begin{cases}a_1 &\mod p_1 \\ a_2 &\mod p_2 \\ &\vdots \\ a_n & \mod p_n\end{cases} x≡⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧a1a2anmodp1modp2⋮modpn,然后让你求出一个最小的x出来。要求所有的 p p p互质。
遇到这种问题以前的我一般会各写几项出来,然后找相同。
这个时候孙子站了出来,他说出:记
P
=
∏
p
P=\prod p
P=∏p,则
x
=
∑
k
=
1
k
=
n
a
k
P
p
k
t
k
x=\sum_{k=1}^{k=n}a_k{\frac{P}{p_k}}t_k
x=∑k=1k=nakpkPtk,
t
k
是
P
p
k
关
于
p
k
的
逆
元
t_k是\frac{P}{p_k}关于p_k的逆元
tk是pkP关于pk的逆元。这是x的一个解,如果你逆元是最小正逆元,那这个x就是最小正解。
为什么呢?
证明啊……。
先
看
x
≡
a
1
m
o
d
p
1
。
先看x\equiv a_1 \mod p_1。
先看x≡a1modp1。
因
为
P
p
1
与
p
1
互
质
,
所
以
肯
定
找
得
到
数
t
1
使
得
P
p
1
t
1
≡
1
m
o
d
p
1
,
这
个
t
1
被
称
为
P
p
1
关
于
p
1
的
逆
元
。
因为\frac{P}{p_1}与p_1互质,所以\href{https://blog.csdn.net/c20182030/article/details/102631472#11_20}{肯定找得到数t_1使得\frac{P}{p_1}t_1\equiv 1\mod p_1},这个t_1被称为\frac{P}{p_1}关于p_1的逆元。
因为p1P与p1互质,所以肯定找得到数t1使得p1Pt1≡1modp1,这个t1被称为p1P关于p1的逆元。
那
么
就
有
x
≡
a
1
≡
a
1
×
1
≡
a
1
P
p
1
p
1
m
o
d
p
1
。
那么就有x\equiv a_1\equiv a_1\times 1\equiv a_1\frac{P}{p_1}p_1\mod p_1。
那么就有x≡a1≡a1×1≡a1p1Pp1modp1。
因
为
P
p
1
=
p
2
×
p
3
×
⋯
×
p
n
,
所
以
有
a
1
P
p
1
p
1
≡
0
(
m
o
d
p
2
)
,
(
m
o
d
p
3
)
,
⋯
,
(
m
o
d
p
n
)
。
因为\frac{P}{p_1}=p_2\times p_3\times \cdots \times p_n,所以有a_1\frac{P}{p_1}p_1\equiv 0 \pmod {p_2},\pmod{p_3},\cdots,\pmod {p_n}。
因为p1P=p2×p3×⋯×pn,所以有a1p1Pp1≡0(modp2),(modp3),⋯,(modpn)。←不标准的表达,应当扣分
以
此
类
推
,
a
2
P
p
2
t
2
就
满
足
模
p
2
时
与
x
同
余
,
模
其
它
p
的
时
候
得
到
0
。
以此类推,a_2\frac{P}{p_2}t_2就满足模p_2时与x同余,模其它p的时候得到0。
以此类推,a2p2Pt2就满足模p2时与x同余,模其它p的时候得到0。
那
么
这
些
东
西
的
和
—
—
s
=
∑
k
=
1
k
=
n
a
k
P
p
k
t
k
,
一
定
满
足
s
≡
a
1
+
0
×
(
n
−
1
)
m
o
d
p
1
,
那么这些东西的和——s=\sum_{k=1}^{k=n}a_k{\frac{P}{p_k}}t_k,一定满足s\equiv a_1+0\times(n-1)\mod p_1,
那么这些东西的和——s=∑k=1k=nakpkPtk,一定满足s≡a1+0×(n−1)modp1,
s
≡
a
2
+
0
×
(
n
−
1
)
m
o
d
p
2
,
s\equiv a_2+0\times(n-1)\mod p_2,
s≡a2+0×(n−1)modp2,
s
≡
a
3
+
0
×
(
n
−
1
)
m
o
d
p
3
,
⋯
,
s\equiv a_3+0\times(n-1)\mod p_3,\cdots,
s≡a3+0×(n−1)modp3,⋯,
s
≡
a
n
+
0
×
(
n
−
1
)
m
o
d
p
n
s\equiv a_n+0\times(n-1)\mod p_n
s≡an+0×(n−1)modpn,所以可以认为
s
s
s是原方程的一个解。那么通解就是
s
+
z
P
,
z
∈
Z
s+zP,z\in \Z
s+zP,z∈Z。
Q.E.D
就这?
代码
洛谷板子题,双倍经验。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
void Read(ll &p)
{
p=0;
int f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
p*=f;
}
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b){d=a,x=1,y=0; return;}
exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
ll n,ans,d,x,y,P=1,a[1024],p[1024];
int main()
{
Read(n);
for(ll i=1;i<=n;i++) Read(p[i]),Read(a[i]),P*=p[i];
for(ll i=1;i<=n;i++) exgcd(P/p[i],p[i],d,x,y),ans+=a[i]*(P/p[i])%p*x,((ans%=P)+=P)%=P;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
void Read(ll &p)
{
p=0;
int f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
p*=f;
}
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b){d=a,x=1,y=0; return;}
exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
ll mul(ll a,ll b,ll p)
{
return ((a*b-(ll)((long double)a/p*b+1e-8)*p)%p+p)%p;
}
ll n,ans,d,x,y,P,a[1024],p[1024];
int main()
{
Read(n),P=1;
for(ll i=1;i<=n;i++) Read(a[i]);
for(ll i=1;i<=n;i++) Read(p[i]),((a[i]%=p[i])+=p[i])%=p[i],P*=p[i];
for(ll i=1;i<=n;i++) exgcd(P/p[i],p[i],d,x,y),ans+=mul(mul(a[i],P/p[i],P),x,P),((ans%=P)+=P)%=P;
printf("%lld\n",ans);
}
EXCRT
现在这些p不一定互质了。
我们先看头两个方程吼,
{
x
≡
a
1
m
o
d
p
1
x
≡
a
2
m
o
d
p
2
\begin{cases}x\equiv a_1\mod p_1\\x\equiv a_2 \mod p_2\end{cases}
{x≡a1modp1x≡a2modp2。
那么就有
x
=
k
1
×
p
1
+
a
1
=
k
2
×
p
2
+
a
2
⇒
k
1
×
p
1
−
k
2
×
p
2
=
a
2
−
a
1
x=k_1\times p_1+a_1=k_2\times p_2+a_2\rArr k_1\times p_1-k_2\times p_2=a_2-a_1
x=k1×p1+a1=k2×p2+a2⇒k1×p1−k2×p2=a2−a1。
令
g
c
d
(
p
1
,
p
2
)
=
g
gcd(p_1,p_2)=g
gcd(p1,p2)=g,则同时除就有
k
1
p
1
g
−
k
2
p
2
g
=
a
2
−
a
1
g
⟺
k
1
p
1
g
≡
a
2
−
a
1
g
m
o
d
p
2
g
k_1\frac{p_1}{g}-k_2\frac{p_2}{g}=\frac{a_2-a_1}{g}\iff k_1\frac{p_1}{g}\equiv \frac{a_2-a_1}{g}\mod {\frac{p_2}{g}}
k1gp1−k2gp2=ga2−a1⟺k1gp1≡ga2−a1modgp2,其中
g
c
d
(
p
1
g
,
p
2
g
)
=
1
gcd(\frac{p_1}{g},\frac{p_2}{g})=1
gcd(gp1,gp2)=1。
注意,如果
g
∤
a
2
−
a
1
g\nmid {a_2-a_1}
g∤a2−a1,则无解。
因为这两个数互质,所以可以求出逆元来,就有:
k
1
≡
a
2
−
a
1
g
×
(
p
1
g
)
−
1
m
o
d
p
2
g
k_1\equiv \frac{a_2-a_1}{g}\times (\frac{p_1}{g})^{-1}\mod \frac{p_2}{g}
k1≡ga2−a1×(gp1)−1modgp2。
所以设
k
1
=
q
×
p
2
g
+
a
2
−
a
1
g
×
(
p
1
g
)
−
1
k_1=q\times \frac{p_2}{g}+\frac{a_2-a_1}{g}\times (\frac{p_1}{g})^{-1}
k1=q×gp2+ga2−a1×(gp1)−1。
知道
k
1
k_1
k1了,我们就知道了
x
x
x。
x
=
k
1
×
p
1
+
a
1
=
(
q
×
p
2
g
+
a
2
−
a
1
g
×
(
p
1
g
)
−
1
)
×
p
1
+
a
1
=
q
×
p
1
p
2
g
+
a
2
−
a
1
g
×
(
p
1
g
)
−
1
×
p
1
+
a
1
x=k_1\times p_1+a_1=\left(q\times \frac{p_2}{g}+\frac{a_2-a_1}{g}\times (\frac{p_1}{g})^{-1}\right) \times p_1+a_1=q\times\frac{p_1p_2}{g}+\frac{a_2-a_1}{g}\times (\frac{p_1}{g})^{-1}\times p_1+a_1
x=k1×p1+a1=(q×gp2+ga2−a1×(gp1)−1)×p1+a1=q×gp1p2+ga2−a1×(gp1)−1×p1+a1
⟺
x
≡
a
2
−
a
1
g
×
(
p
1
g
)
−
1
×
p
1
+
a
1
m
o
d
p
1
p
2
g
\iff x\equiv\frac{a_2-a_1}{g}\times (\frac{p_1}{g})^{-1}\times p_1+a_1 \mod \frac{p_1p_2}{g}
⟺x≡ga2−a1×(gp1)−1×p1+a1modgp1p2。
我们把两个同余式合成了一个,太棒了。
看来我们可以做很多次,最后得到一个方程
x
≡
A
m
o
d
B
x\equiv A\mod B
x≡AmodB。
x
x
x肯定可以随便解了。
代码
洛谷板子题,【模板】扩展中国剩余定理(EXCRT)。
居然一次过编译过样例,还直接A掉了。
我佛了。
太丑了。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
void Read(ll &p)
{
p=0;
int f=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9')
p=p*10+c-'0',c=getchar();
p*=f;
}
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
if(!b){d=a,x=1,y=0; return;}
exgcd(b,a%b,d,y,x),y-=(a/b)*x;
}
ll mul(ll a,ll b,ll p)
{
return ((a*b-(ll)((long double)a/p*b+1e-8)*p)%p+p)%p;
}
ll n,A,B,C,D,E,d,p,x,y;
int main()
{
Read(n),n--,Read(B),Read(A);
while(n--) Read(D),Read(C),d=gcd(B,D),exgcd(B/d,D/d,p,x,y),E=B/d*D,(A+=mul(mul((C-A)/d,x,E),B,E))%=E,B=E;
printf("%lld\n",(A%B+B)%B);
}
CanKaoWenXian
CRT:其实是在我看了好几篇举个例子就说自己证好了的博客以后,再看到这篇博客的时候突然懂了,所以就以这篇博客为参考文献了。不过这篇文章确实给了我参考。
说在后面
问了问数竞的同学,他们的中国剩余定理是证明其有解,然后数学归纳法就整出来了。
好吧,他们确实算不出来逆元。