目录
- 整除
- 质数
- 积性函数
- 模算术
整除
一般情况下暂不讨论负数
任何正整数都整除于0
若
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1,则称
a
a
a与
b
b
b互质
g c d gcd gcd与 l c m lcm lcm的关系:
l c m ( a , b ) = a b g c d ( a , b ) lcm(a,b)=\frac{ab}{gcd(a,b)} lcm(a,b)=gcd(a,b)ab
g c d gcd gcd的性质
- g c d ( a , b ) = g c d ( b , a − b ) gcd(a,b)=gcd(b,a-b) gcd(a,b)=gcd(b,a−b)
- g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)
求 g c d gcd gcd的代码
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
复杂度为 O ( log max ( a , b ) ) O(\log \max(a,b)) O(logmax(a,b))
质数
质数个数
公式:
定义
π
(
n
)
\pi(n)
π(n)为不大于
n
n
n的质数的个数,则:
π
(
n
)
=
O
(
n
log
n
)
\pi(n)=O(\frac{n}{\log n})
π(n)=O(lognn)
n
n
n越大,答案越精准
唯一分解定理
对于任意一个
n
≥
2
n \geq 2
n≥2,都有这样的唯一的分解式:
n
=
∏
i
=
1
m
p
i
k
i
n=\prod_{i=1}^{m}{p_{i}^{k_i}}
n=i=1∏mpiki
其中,
p
i
p_{i}
pi为不大于
n
n
n的质数,
k
i
k_{i}
ki为正整数
可以证明,
m
=
O
(
log
log
n
)
m=O(\log\log n)
m=O(loglogn)
质因数分解代码
//法一
for(int i=2;i<=n;++i)
{
while(n%i==0)
{
num[++cnt]=i;
n/=i;
}
}
//法二
for(int i=2;i*i<=n;++i)
{
while(n%i==0)
{
num[++cnt]=i;
n/=i;
}
}
if(n>1)num[++cnt]=n;
//法三
vector<int>p;//存储所有的质数
for(int i=1;i<p.size();++i)
{
if(p[i]*p[i]>n)break;
while(n%p[i]==0)
{
num[++cnt]=p[i];
n/=p[i];
}
}
if(n>1)num[++cnt]=n;
法一的复杂度为
O
(
n
)
O(n)
O(n)
法二的复杂度为
O
(
n
)
O(\sqrt n)
O(n)
法三的复杂度为
O
(
n
log
n
)
O(\frac{\sqrt n}{\log n})
O(lognn)
求所有不大于 n n n的质数
筛法:
- 朴素筛:复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
- 埃氏筛:复杂度为 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
- 欧拉筛:复杂度为 O ( n ) O(n) O(n)
欧拉筛代码:
bool vis[N];
int num[N]
vis[1]=1;
for(int i=1;i<=n;++i)
{
if(!vis[i])num[++cnt]=i;
for(int j=1;j<=cnt&&num[j]*i<=n;++j)
{
vis[i*num[j]]=1;
if(i%num[j]==0)break;
}
}
积性函数
定义
设
f
(
n
)
f(n)
f(n)为定义在正整数上的函数(一般数论函数较多),如果
f
(
1
)
=
1
f(1)=1
f(1)=1,且对于任意的正整数
a
,
b
a,b
a,b,若
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1,,就有:
f
(
a
∗
b
)
=
f
(
a
)
∗
f
(
b
)
f(a*b)=f(a)*f(b)
f(a∗b)=f(a)∗f(b)
我们称
f
(
n
)
f(n)
f(n)为积性函数
若不要求
a
,
b
a,b
a,b互质,这样的
f
(
n
)
f(n)
f(n)称为完全积性函数
计算方法
首先是得到 n n n的唯一分解式: n = ∏ i = 1 m p i k i n=\prod_{i=1}^{m}{p_{i}^{k_{i}}} n=∏i=1mpiki
根据积性函数的性质可以得到以下计算式:
f
(
n
)
=
∏
i
=
1
m
p
i
k
i
f(n)=\prod_{i=1}^{m}{p_{i}^{k_i}}
f(n)=i=1∏mpiki
求解
f
(
p
i
k
i
)
f(p_{i}^{k_{i}})
f(piki)的方法由积性函数的性质决定,无一般方法求解
线性筛的过程中求解积性函数
bool vis [ N+1];
vector p ;
int c [ N+1], f [ N+1];
void sieve()
{
for (int i = 2; i <= N; ++ i)
{
if(!vis [ i])
{
p .push_back ( i);
for (int j = i , k = 1;; ++ k)
{
c [ j] = j ;
f [ j] = cal ( i , k);
if ( j > N / i ) break ;
j *= i ;
}
}
for (int j = 0; i * p [ j] <= N; ++ j)
{
vis [ i * p [ j]] = 1;
if ( i % p [ j] == 0)
{
c [ i * p [ j]] = c [ i]* p [ j];
f [ i * p [ j]] = f [ i / c [ i]]* f [ c [ i]* p [ j]];
break ;
}
c [ i * p [ j]] = p [ j];
f [ i * p [ j]] = f [ i]* f [ p [ j]];
}
}
}
积性函数举例
约数函数
定义
σ
x
(
n
)
\sigma _{x}(n)
σx(n)为
n
n
n的所有约数的
x
x
x次方的和,即:
σ
x
(
n
)
=
∑
d
∣
n
d
x
\sigma _{x}(n)=\sum_{d\mid n}{d^{x}}
σx(n)=d∣n∑dx
特别的,
σ
0
(
n
)
\sigma _{0}(n)
σ0(n)表示的是
n
n
n的约数的个数,常常记为
d
(
n
)
d(n)
d(n)或
τ
(
n
)
\tau(n)
τ(n),
σ
1
(
n
)
\sigma _{1}(n)
σ1(n)表示的是约数和,简记为
σ
(
n
)
\sigma(n)
σ(n)
具体来说,对于
n
n
n的每一个质因子,我们都可以得到这样的式子:
τ
(
p
k
)
=
l
+
1
\tau(p^{k})=l+1
τ(pk)=l+1
(+1的原因是要考虑1)
然后,我们把
n
n
n的唯一分解式带入后,根据乘法原理就可以得到
τ
(
n
)
\tau(n)
τ(n)的计算式:
τ
(
n
)
=
∏
i
=
1
m
k
i
+
1
\tau(n)=\prod_{i=1}^{m}{k_{i}+1}
τ(n)=i=1∏mki+1
由此可以证明
σ
0
(
n
)
\sigma _{0}(n)
σ0(n)为积性函数
对于质数
p
p
p和正整数
k
k
k,有:
σ
x
(
p
k
)
=
∑
i
=
0
k
(
p
i
)
x
=
∑
i
=
0
k
(
p
x
)
i
\sigma_{x}(p^{k})=\sum_{i=0}^{k}(p^{i})^{x}=\sum_{i=0}^{k}(p^{x})^i
σx(pk)=i=0∑k(pi)x=i=0∑k(px)i
因此,当
x
≠
0
x\neq0
x=0时,有:
σ
x
(
p
k
)
=
(
p
x
)
k
+
1
−
1
p
x
−
1
\sigma_{x}(p^{k})=\frac{(p^{x})^{k+1}-1}{p^{x}-1}
σx(pk)=px−1(px)k+1−1
欧拉函数
定义
φ
(
n
)
\varphi (n)
φ(n) 为不大于
n
n
n的数中与
n
n
n互质的数的个数,即:
φ
(
n
)
=
∑
i
=
1
n
[
g
c
d
(
i
,
n
)
=
1
]
\varphi (n)=\sum_{i=1}^{n}[gcd(i,n)=1]
φ(n)=i=1∑n[gcd(i,n)=1]
[
x
]
[x]
[x]在
x
x
x为真时值为
1
1
1
对于质数
p
p
p和正整数
k
k
k,有:
φ
(
p
k
)
=
p
k
−
p
k
−
1
=
p
k
−
1
∗
(
p
−
1
)
\varphi (p^{k})=p^{k}-p^{k-1}=p^{k-1}*(p-1)
φ(pk)=pk−pk−1=pk−1∗(p−1)
可以证明
φ
(
n
)
\varphi (n)
φ(n)为积性函数
欧拉函数的计算公式:
φ
(
n
)
=
n
∏
p
∣
n
(
1
−
1
p
i
)
\varphi(n)=n\prod_{p\mid n}(1-\frac{1}{p_{i}})
φ(n)=np∣n∏(1−pi1)
欧拉函数的性质:
- ∑ d ∣ n φ ( d ) = n \sum_{d\mid n}\varphi(d)=n ∑d∣nφ(d)=n
- 若 n n n为质数, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n−1
- 若 gcd ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1,则 φ ( a b ) = φ ( a ) φ ( b ) \varphi(ab)=\varphi(a)\varphi(b) φ(ab)=φ(a)φ(b)
欧拉函数的求解:
求解单个欧拉函数的值:
int tmp=phi_m=m;
for(int i=2;i<=m;++i)
{
if(i*i>m)break;
if(tmp%i==0)
{
phi_m=phi_m-phi_m/i;
while(tmp%i==0)tmp/=i;
}
}
if(tmp>1)phi_m=phi_m-phi_m/tmp;
线性递推求解多个欧拉函数的值:
void phi_n()
{
phi[1]=1;
for(int i=2;i<=N-10;++i)
{
if(!vis[i])
{
phi[i]=i-1;
p.push_back(i);
}
for(int j=0;j<p.size()&&p[j]*i<=N-10;++j)
{
vis[i*p[j]]=1;
if(i%p[j]==0)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
else phi[i*p[j]]=phi[i]*phi[p[j]];
}
}
}
模算术
取模
注意取模的定义(特指负数形式下)
a
m
o
d
n
=
{
a
−
⌊
a
n
⌋
a
≥
0
−
(
−
a
m
o
d
n
)
a
<
0
a\,\,mod\,\,n=\begin{cases} a-\lfloor \frac {a}{n} \rfloor & a\geq 0\\\\ -(-a\,\,mod\,\,n) & a\lt 0 \end{cases}
amodn=⎩
⎨
⎧a−⌊na⌋−(−amodn)a≥0a<0
同余
若
(
a
−
b
)
m
o
d
n
=
0
(a - b)\,\,mod\,\,n=0
(a−b)modn=0,则称
a
a
a和
b
b
b同余,记作:
a
≡
b
(
m
o
d
n
)
a\equiv b\,\,(mod\,\,n)
a≡b(modn)
当
a
a
a和
b
b
b均取正整数时,此式等价于
a
m
o
d
n
=
b
m
o
d
n
a\,\,mod\,\,n=b\,\,mod\,\,n
amodn=bmodn
根据模运算的性质可得到同余的等价形式:
a
≡
b
(
m
o
d
n
)
⟺
n
∣
(
a
−
b
)
a\equiv b(\bmod n) \Longleftrightarrow n \mid (a-b)
a≡b(modn)⟺n∣(a−b)
根据模运算的定义可以得到几个几个同余的性质:
假设 a ≡ b ( m o d n ) a \equiv b(mod n) a≡b(modn) 且 c ≡ d ( m o d n ) c\equiv d(\bmod n) c≡d(modn),可以得知:
- a + c ≡ b + d ( m o d n ) a+c \equiv b+d (\bmod n) a+c≡b+d(modn)
- a c ≡ b d ( m o d n ) ac \equiv bd(\bmod n) ac≡bd(modn)
- k a ≡ k b ( m o d n ) ka\equiv kb(\bmod n) ka≡kb(modn)
- a m ≡ b m ( m o d n ) a^{m}\equiv b^{m}\,\,(\bmod n) am≡bm(modn)
- 若 a b ≡ a c ( m o d n ) ab\equiv ac(\bmod n) ab≡ac(modn),且 gcd ( a , n ) = 1 \gcd(a,n)=1 gcd(a,n)=1,则 b ≡ c ( m o d n ) b\equiv c(\bmod n) b≡c(modn),满足消去律
剩余类
把所有模 n n n后与 a a a同余的整数构成的集合叫做一个剩余类,记作 [ a ] [a] [a]
根据同余的性质可以推得: a ≡ b ( m o d n ) ⇔ [ a ] = [ b ] a\equiv b(\bmod n) \Leftrightarrow [a]=[b] a≡b(modn)⇔[a]=[b]
剩余类的运算满足:交换律、结合律,分配律
即: [ a ] + [ b ] = [ a + b ] , [ a ] ∗ [ b ] = [ a ∗ b ] [a]+[b]=[a+b],[a]*[b]=[a*b] [a]+[b]=[a+b],[a]∗[b]=[a∗b]
模算术的基本性质
设
a
0
=
a
m
o
d
n
a_{0}=a\,\,mod\,\,n
a0=amodn,
b
0
=
b
m
o
d
n
b_{0}=b\,\,mod\,\,n
b0=bmodn,有:
a
+
b
≡
a
0
+
b
0
(
m
o
d
n
)
a
∗
b
≡
a
0
∗
b
0
(
m
o
d
n
)
\begin{split} a+b\equiv a_{0}+b_{0}\,\,(mod\,\,n)\\ a*b\equiv a_{0}*b_{0}\,\,(mod\,\,n) \end{split}
a+b≡a0+b0(modn)a∗b≡a0∗b0(modn)
对于任意的正整数
k
k
k,有:
a
m
o
d
n
=
(
a
m
o
d
k
n
)
m
o
d
n
a\,\,mod\,\,n=(a\,\,mod\,\,kn)mod\,\,n
amodn=(amodkn)modn
若有
k
∣
n
k\mid n
k∣n,则:
a
k
m
o
d
n
=
a
m
o
d
k
n
k
\frac{a}{k}\,\,mod\,\,n=\frac{a\,\,mod\,\,kn}{k}
kamodn=kamodkn
证明如下:
设 a = m k a=mk a=mk
a k m o d n = m m o d n = m − n a m o d k n k = a − k n k = k ( m − n ) k = m − n \begin{split} \frac{a}{k}\,\,mod \,\,n=m \,\,mod \,\,n\\=m-n \\ \frac{a\,\, mod \,\,kn}{k}=\frac{a-kn}{k}\\\\=\frac{k(m-n)}{k}\\\\=m-n \end{split} kamodn=mmodn=m−nkamodkn=ka−kn=kk(m−n)=m−n
模算术的基本运算
取模优化
template <class>T
inline T mod(T a)
{
return a<p?a:a-p;
}
这个函数的速度优于内置的取模运算符,但不可以代替取模(仅仅在 a < 2 p a\lt 2p a<2p时可以使用)
快速幂(平方求幂法)
int power(int a, int b,int mod)
{
int bas=a,num=1;
while(b)
{
if(b&1) num = (num*bas)%mod;
bas=(bas*bas)%mod;
b>>=1;
}
return num;
}
龟速(快速)乘(加倍求积法)
#define int long long
int mul(int a, int b,int mod)
{
int num = 0;
while(b)
{
if(b&1) num =(num+a)%mod;
if(b>1) a =(a+a)%mod;
b>>=1;
}
return num;
}
龟速乘的主要用途是为了防止炸精度,从而以牺牲时间复杂度为代价进行加倍求积
模乘法的逆元
逆元存在的意义是分数无法直接取模
设
a
a
a为正整数,若存在整数
b
b
b满足:
a
∗
b
≡
1
(
m
o
d
n
)
a\,*\,b\equiv1 \,\,(\,\,mod\,\,n)
a∗b≡1(modn)
则称
b
b
b为
a
a
a模
n
n
n的逆元,记为
a
−
1
a^{-1}
a−1或
1
a
\frac{1}{a}
a1
-
当且仅当 g c d ( a , n ) = 1 gcd(a,n)=1 gcd(a,n)=1时, a a a模 n n n的逆元存在
-
a a a模 n n n的逆元在模 n n n意义下具有唯一性
费马小定理
设
p
p
p为质数,
a
a
a与
p
p
p互质,则有:
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p-1}\equiv 1\,\,(\,\,mod\,\,p)
ap−1≡1(modp)
证明如下:
已知 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1,我们取一个数列如下:
1
,
2
,
…
,
p
−
1
1,2,\dots , p-1
1,2,…,p−1集体乘
a
a
a再模
p
p
p可以得到:
a
,
2
a
,
…
,
(
p
−
1
)
a
m
o
d
p
→
1
,
2
,
…
,
p
−
1
a,2a,\dots,(p-1)a \bmod p\,\,\to 1,2,\dots,p-1
a,2a,…,(p−1)amodp→1,2,…,p−1
因为
a
,
2
a
,
…
,
(
p
−
1
)
a
a,2a,\dots,(p-1)a
a,2a,…,(p−1)a为
p
−
1
p-1
p−1个互不相同的数,模
p
p
p后势必得到
p
p
p个不同的数,因此可以得到上式
由上式我们可以得到:
1
×
2
×
⋯
×
(
p
−
1
)
≡
a
×
2
a
×
⋯
×
(
p
−
1
)
a
(
m
o
d
p
)
1\times2\times\dots\times(p-1)\equiv a\times2a\times\dots\times(p-1)a\,\,(\bmod p)
1×2×⋯×(p−1)≡a×2a×⋯×(p−1)a(modp)
即:
(
p
−
1
)
!
≡
a
p
−
1
(
p
−
1
)
!
(
m
o
d
p
)
(p-1)\,!\,\,\equiv a^{p-1}(p-1)\,!\,\,(\bmod p)
(p−1)!≡ap−1(p−1)!(modp)
又因为
g
c
d
(
p
,
p
−
1
)
=
1
gcd(p,p-1)=1
gcd(p,p−1)=1,原式推导可得:
1
≡
a
p
−
1
(
m
o
d
p
)
1\equiv a^{p-1}\,\,(\bmod p)
1≡ap−1(modp)
证毕
注意:同余式可以两端同时乘逆元
由费马小定理可以得知:
a
∗
a
p
−
2
≡
1
(
m
o
d
p
)
a*a^{p-2}\equiv 1(\bmod p)
a∗ap−2≡1(modp)
根据乘法逆元的定义可以得知:
a
−
1
≡
a
p
−
2
(
m
o
d
p
)
a^{-1}\equiv a^{p-2} (\bmod p)
a−1≡ap−2(modp)
由此,我们可以根据费马小定理,利用快速幂求解逆元
预处理逆元
假设 p p p为质数, n n n为正整数,求 [ 1 , n ] [1,n] [1,n]每个数模 p p p意义下的逆元
对每个数分别求逆元,时间复杂度为 O ( n l o g p ) O(nlogp) O(nlogp)
我们可以发现,逆元满足积性函数,因此可以用线性筛去求解,时间复杂度为 O ( n log p log n ) O(\frac{n\log p}{\log n}) O(lognnlogp)
(关于逆元是积性函数的证明,显然有 ( a b ) − 1 = a − 1 b − 1 (ab)^{-1}=a^{-1}b^{-1} (ab)−1=a−1b−1)
但显然我们有更优的方法
我们设
i
∈
[
1
,
n
]
i \in [1,n]
i∈[1,n],根据模运算的性质我们可以得到:
p
=
⌊
p
i
⌋
i
+
(
p
m
o
d
i
)
p=\lfloor \frac{p}{i} \rfloor i \,\,+\,\,(p\bmod i)
p=⌊ip⌋i+(pmodi)
对该式移项化简可以得到:
i
−
1
≡
−
⌊
p
i
⌋
p
m
o
d
i
(
m
o
d
p
)
{i}^{-1}\equiv -\frac{\lfloor \frac{p}{i}\rfloor }{p\bmod i} (\bmod p)
i−1≡−pmodi⌊ip⌋(modp)
因为
p
m
o
d
i
<
i
p \bmod i \lt i
pmodi<i,因此递推计算的时间复杂度为
O
(
n
)
O(n)
O(n)
以上方法推导简单,但不是最优的方法
一个明显的等式 1 i ! = i + 1 ( i + 1 ) ! \frac{1}{i!}=\frac{i+1}{(i+1)!} i!1=(i+1)!i+1,因此实际上,我们可以用 O ( log p ) O(\log p) O(logp)的复杂度求出 1 n ! \frac{1}{n!} n!1,接下来进行递推便可得到任意的 1 i ! \frac{1}{i!} i!1,由此可以得到 1 i \frac{1}{i} i1
欧拉定理
设
n
≥
2
n\geq 2
n≥2为整数,
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1,则有:
a
φ
(
n
)
≡
1
(
m
o
d
n
)
a^{\varphi(n)}\equiv1 (mod\,\,n)
aφ(n)≡1(modn)
特别的,若 n n n为质数, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n−1,欧拉定理便转化为费马小定理
用类似的方法可以得到:
a
−
1
≡
a
φ
(
n
)
−
1
(
m
o
d
n
)
a^{-1}\equiv a^{\varphi(n)-1}\,\,(\bmod n)
a−1≡aφ(n)−1(modn)
利用这个式子便可以求任意模数下的逆元,但计算 φ ( n ) \varphi(n) φ(n)的复杂度较高( O ( n log n ) O(\sqrt n\log n) O(nlogn)),该式不如费马小定理常用
扩展欧拉定理
对于欧拉定理,我们可以将
a
a
a的指数一般化,得到一下情况
a
b
≡
{
a
b
m
o
d
φ
(
m
)
(
m
o
d
m
)
gcd
(
a
,
m
)
=
1
a
b
(
m
o
d
m
)
gcd
(
a
,
m
)
≠
1
,
b
<
φ
(
m
)
a
(
b
m
o
d
φ
(
m
)
)
+
φ
(
m
)
(
m
o
d
m
)
gcd
(
a
,
m
)
≠
1
,
b
≥
φ
(
m
)
a^{b}\equiv \begin{cases} a^{b\bmod \varphi(m)}\,(\bmod m)\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\gcd(a,m)=1\\ \\ a^{b}\,(\bmod m)\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\gcd(a,m)\neq1,b\lt \varphi(m)\\ \\ a^{(b\bmod \varphi(m))+\varphi(m)}\,(\bmod m)\,\,\,\,\,\,\,\,\,\,\gcd(a,m)\neq1,b\geq\varphi(m) \end{cases}
ab≡⎩
⎨
⎧abmodφ(m)(modm)gcd(a,m)=1ab(modm)gcd(a,m)=1,b<φ(m)a(bmodφ(m))+φ(m)(modm)gcd(a,m)=1,b≥φ(m)
降幂公式
设
n
,
k
n,k
n,k为任意的正整数,
a
a
a为任意整数,可以得到:
a
k
≡
a
min
(
k
,
k
0
)
(
m
o
d
n
)
a^{k}\equiv a^{\min(k,k_{0})}\,\,(\bmod n)
ak≡amin(k,k0)(modn)
其中,
k
0
=
(
k
m
o
d
φ
(
n
)
)
+
φ
(
n
)
k_{0}=(k\bmod \varphi(n))+\,\,\varphi(n)
k0=(kmodφ(n))+φ(n)
由此我们就可以实现降幂的操作,从而降低时间复杂度
欧拉降幂
根据扩展欧拉定理,我们可以对于降幂的操作分三类情况进行讨论,然后分别进行降幂操作
代码如下:
int read()
{
int b=0;
bool flag=0;
char c;
while (!isdigit(c = getchar()));
for (; isdigit(c); c = getchar()) //由于读入的系数会很大,因此要一边读入一边取模降幂
{
b = b * 10 + c - '0';
if (b >= phi)
{
flag = true;
b %= phi;
}
}
if (flag)
{
b += phi ;
}
return b;
}
欧几里得算法与扩展欧几里得算法
欧几里得算法(辗转相除法)
设
a
,
b
a,b
a,b为任意正整数且
a
>
b
a\gt b
a>b,则存在正整数组
q
,
r
q,r
q,r满足:
a
=
q
0
b
+
r
0
b
=
q
1
r
0
+
r
1
r
0
=
q
1
r
1
+
r
2
…
…
r
n
−
2
=
q
n
r
n
−
1
+
r
n
r
n
−
1
=
q
n
+
1
r
n
\begin{split} a=q_{0}b+r_{0}\\ b=q_{1}r_{0}+r_{1}\\ r_{0}=q_{1}r_{1}+r_{2}\\ \dots \dots\\ r_{n-2}=q_{n}r_{n-1}+r_{n}\\ r_{n-1}=q_{n+1}r_{n} \end{split}
a=q0b+r0b=q1r0+r1r0=q1r1+r2……rn−2=qnrn−1+rnrn−1=qn+1rn
其中,
b
>
r
0
>
r
1
>
˙
r
n
b \gt r_{0}\gt r_{1}\dot \gt r_{n}
b>r0>r1>˙rn
以上的一组式子实际上是 求解 gcd ( a , b ) \gcd(a,b) gcd(a,b)的展开
扩展欧几里得算法
通过以上的式子我们可以总结得出,对于任意的正整数
k
k
k,都会满足:
r
k
=
r
k
−
2
−
q
k
r
k
−
1
r_{k}=r_{k-2}-q_{k}r_{k-1}
rk=rk−2−qkrk−1
因此,我们可以通过递归求解出整数(可以为负数)
x
,
y
x,y
x,y,满足:
r
n
=
a
x
+
b
y
r_{n}=ax+by
rn=ax+by
特别的,当 gcd ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1时,原式可化简为 a x ≡ 1 ( m o d b ) ax\equiv 1(\bmod b) ax≡1(modb),此时, x x x为 a a a在模 b b b意义下的逆元
扩欧代码:
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int d=gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
当 b = 0 b=0 b=0时,我们显然有一组解 x = 1 , y = 0 x=1,y=0 x=1,y=0
当 b > 0 b\gt 0 b>0时,由 gcd ( a , b ) = g c d ( b , a m o d b ) \gcd(a,b)=gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)可知:假设存在 x , y x,y x,y满足 a x + gcd ( b , a m o d b ) y = gcd ( b , a m o d b ) ax+\gcd(b,a\bmod b)y=\gcd(b,a\bmod b) ax+gcd(b,amodb)y=gcd(b,amodb)
那么就有 a y + b ( x − ⌊ a b ⌋ ) = gcd ( a , b ) ay+b(x-\lfloor\frac{a}{b}\rfloor)=\gcd(a,b) ay+b(x−⌊ba⌋)=gcd(a,b)
裴蜀定理
对于任意的正整数 a , b a,b a,b,都存在 x , y x,y x,y满足 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)
裴蜀定理也可以扩展到 n n n个正整数,即:
对于任意
n
n
n个正整数
a
1
,
a
2
,
…
,
a
n
a_{1},a_{2},\dots,a_{n}
a1,a2,…,an,都存在
n
n
n个整数
x
1
,
x
2
,
…
,
x
n
x_{1},x_{2},\dots,x_{n}
x1,x2,…,xn,满足:
a
1
x
1
+
a
2
x
2
+
⋯
+
a
n
x
n
=
gcd
(
a
1
,
a
2
,
…
,
a
n
)
a_{1}x_{1}+a_{2}x_{2}+\dots+a_{n}x_{n}=\gcd(a_{1},a_{2},\dots,a_{n})
a1x1+a2x2+⋯+anxn=gcd(a1,a2,…,an)
这个方程亦可用扩欧进行求解
扩欧最常用的一个方面是求解不定方程 a x + b y = c ax+by=c ax+by=c
根据裴蜀定理可以得到:
若 c ∣ gcd ( a , b ) c\mid \gcd(a,b) c∣gcd(a,b),该方程肯定有整数解
我们可以求出
a
x
+
b
y
=
gcd
(
a
,
b
)
ax+by=\gcd(a,b)
ax+by=gcd(a,b)的一组特解
(
x
′
,
y
′
)
(x',y')
(x′,y′),然后得到了
a
x
+
b
y
=
c
ax+by=c
ax+by=c的一组特解:
(
c
gcd
(
a
,
b
)
x
′
,
c
gcd
(
a
,
b
)
y
′
)
(\frac{c}{\gcd(a,b)}x',\frac{c}{\gcd(a,b)}y')
(gcd(a,b)cx′,gcd(a,b)cy′)
最后可以得到该方程的通解:
( c gcd ( a , b ) x ′ + k b gcd ( a , b ) , c gcd ( a , b ) y ′ − k a gcd ( a , b ) ) (\frac{c}{\gcd(a,b)}x'+k \frac{b}{\gcd(a,b)} ,\frac{c}{\gcd(a,b)}y'-k\frac{a}{\gcd(a,b)}) (gcd(a,b)cx′+kgcd(a,b)b,gcd(a,b)cy′−kgcd(a,b)a)
中国剩余定理( C R T CRT CRT)
问题背景:
求解同余方程组:
{
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
…
…
x
≡
a
n
(
m
o
d
m
n
)
\begin{cases} x\equiv a_{1}(\bmod m_{1})\\ x\equiv a_{2}(\bmod m_{2})\\ \dots \dots\\ x\equiv a_{n}(\bmod m_{n}) \end{cases}
⎩
⎨
⎧x≡a1(modm1)x≡a2(modm2)……x≡an(modmn)
其中, m 1 , m 2 … , m n m_{1},m_{2}\dots,m_{n} m1,m2…,mn两两互质
对此我们可以去构造一组解
设
M
=
∏
i
=
1
n
m
i
M=\prod _{i=1}^{n}m_{i}
M=∏i=1nmi,我们可以构造:
x
=
∑
i
=
1
n
M
i
(
a
i
M
i
−
1
m
o
d
m
i
)
x=\sum_{i=1}^{n}M_{i}(a_{i}M_{i}^{-1}\bmod m_{i})
x=i=1∑nMi(aiMi−1modmi)
其中, M i M_{i} Mi表示 M m i \frac{M}{m_{i}} miM,可以证明该解在模 M M M意义下唯一
代码实现:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,ans;
int a[100100],b[100100];
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;
}//利用exgcd求逆元(费马小定理可能不适用)
signed main()
{
scanf("%lld",&n);
int M=1;
for(int i=1;i<=n;++i)
{
scanf("%lld%lld",&b[i],&a[i]);
M*=b[i];//构造M
}
for(int i=1;i<=n;++i)
{
int mod=b[i],mi=M/b[i];
int x=0,y=0;
exgcd(mi,mod,x,y);//x为Mi的逆元
ans=(ans+a[i]*mi*(x<0?x+b[i]:x));
}
printf("%lld",ans%M);
return 0;
}
扩展 C R T CRT CRT
问题背景:求解同余方程组
x
=
a
i
(
m
o
d
m
i
)
x=a_{i}(\bmod m_{i})
x=ai(modmi)
此时不要求
m
i
m_{i}
mi两两互质
对于每一个 m i m_{i} mi,我们对其进行质因数分解,得到 m i = ∏ p i , j k i , j m_{i}=\prod p_{i,j}^{k_{i,j}} mi=∏pi,jki,j ,然后将原方程进行拆分。对于 p p p相同的方程进行合并,从而转化为模数两两互质的方程组。若合并时出现矛盾,则原方程组无解