1、欧拉函数
计算单个值的欧拉函数
- 基于公式:$phi(n) = n* \frac{p_1-1}{p_1} * \frac{p_2-1}{p_2}*\dots *\frac{p_n-1}{p_n}
其中
其中
为
为
- 写代码用试除法可以快速求解
O
(
s
q
r
t
(
n
)
)
O(sqrt(n))
- 基于公式:$phi(n) = n* \frac{p_1-1}{p_1} * \frac{p_2-1}{p_2}*\dots *\frac{p_n-1}{p_n}
筛法求欧拉函数(线性筛)
- 代码如下:
for i in range(2,n+1): if st[i]==0: primes.append(i) phi[i]=i-1 # 质数的phi(i)=i-1 for j in range(len(primes)): if primes[j]*i>n:break st[primes[j]*i]=1 if i%primes[j]==0: phi[i*primes[j]] = phi[i]*primes[j] # primes[j]是i的质因素数 break phi[i*primes[j]] = phi[i]*(primes[j]-1) # primes[j]不是i的质因数
欧拉降幂
- 基本公式
a
b
≡
{
a
b
m
o
d
φ
(
m
)
,
g
c
d
(
a
,
m
)
=
1
,
a
b
,
g
c
d
(
a
,
m
)
≠
1
,
b
<
φ
(
m
)
,
(
m
o
d
m
)
a
(
b
m
o
d
φ
(
m
)
)
+
φ
(
m
)
,
g
c
d
(
a
,
m
)
≠
1
,
b
≥
φ
(
m
)
.
a^b \equiv \begin{cases} a^{b \ mod \ \varphi(m)}, \ \ \ \ \ \ \ \ \ \ \ \ \ gcd(a,m)=1, \ a^b, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ gcd(a,m)
ot=1,b<\varphi(m),\ \ \ \ (mod \ \ m)\ a^{(b \ mod \ \varphi(m)) + \varphi(m)}, \ \ gcd(a,m)
ot =1,b\ge \varphi(m). \end{cases}
- 基本公式
2、乘法逆元
费马小定理求逆元
p
o
w
(
a
,
p
,
p
−
2
)
pow(a,p,p-2)
扩展欧几里得算法求逆元
e
x
g
c
d
(
a
,
p
,
x
,
y
)
exgcd(a,p,x,y)
- 如果求得最大公约数不是1则无解,否则逆元就是
x
x%p
def exgcd(a,b,x,y): if b==0: return a,1,0 d,x,y = exgcd(b,a%b,x,y) x,y = y,x-a//b*y return d,x,y
3、中国剩余定理
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 \pmod{m_1} \ x \equiv a_2 \pmod{m_2} \ \qquad \vdots \ x \equiv a_n \pmod{m_n} \end{cases}
⎩
⎨
⎧x≡a1(modm1)x≡a2(modm2)⋮x≡an(modmn)
- 在中国剩余定理中:
a
1
,
a
2
,
…
,
a
n
a_1, a_2, \ldots, a_n
m
1
,
m
2
,
…
,
m
n
m_1,m_2,\ldots,m_n
C
R
T
CRT
CRT问题的解决方法
CRT主要利用
m
1
,
m
2
,
…
,
m
n
m_1,m_2,\dots,m_n
m1,m2,…,mn 为两两互质的整数的性质。我们可以令:
M
=
m
1
×
m
2
×
⋯
×
m
n
=
∏
i
=
1
n
m
i
M
i
=
M
/
m
i
M=m_1 imes m_2 imes \dots imes m_n = \begin{equation} \prod_{i=1}^{n}m_i \end{equation}\ M_i = M/m_i
M=m1×m2×⋯×mn=i=1∏nmiMi=M/mi
明显这里的M
i
M_i
Mi是和
m
i
m_i
mi互质的。
接着我们定义逆元:
t
i
=
M
i
−
1
t_i = M_i^{-1}
ti=Mi−1
所以我们可以构造出一个解
x
0
x_0
x0
x
0
=
∑
i
=
1
n
a
i
M
i
t
i
x_0 = \sum_{i=1}^{n}a_iM_it_i
x0=i=1∑naiMiti
解释
∀
j
∈
[
1
,
n
]
\forall j \in [1,n]
∀j∈[1,n]:
{
a
j
M
j
t
j
%
m
i
=
0
j
≠
i
a
j
M
j
t
j
%
m
i
=
a
i
j
=
i
\begin{cases} a_jM_jt_j \% m_i = 0 \ \ \ \ \ \ j
eq i \ a_jM_jt_j \% m_i = a_i \ \ \ \ \ j=i \end{cases}{ajMjtj%mi=0 j=iajMjtj%mi=ai j=i
通解就是
x
=
x
0
+
k
M
x = x_0 + kM
x=x0+kM,而CRT问题所求的最小整数解其实就是
a
n
s
=
x
%
M
ans = x \% M
ans=x%M
E
X
C
R
T
EXCRT
EXCRT扩展中国剩余定理的基本用法性质
同余方程合并后模数是原来模数的最小公倍数。
合并的流程:
假设前
k
−
1
k-1
k−1个同余方程合并得到新的方程为:
x
=
r
1
(
m
o
d
M
)
x = r_1 \pmod{M}
x=r1(modM) ,
M
M
M是前
k
−
1
k-1
k−1个同余方程模数的最小公倍数,现在需要考虑合并第
k
k
k个方程:
x
=
r
2
(
m
o
d
m
k
)
x = r_2 \pmod{m_k}
x=r2(modmk)。
对于前
k
−
1
k-1
k−1个同余方程,其通解为
x
=
r
1
+
i
∗
M
,
i
∈
Z
x=r_1+i*M,i \in Z
x=r1+i∗M,i∈Z,接着在通解里面找到一个
t
t
t,使得
(
r
1
+
t
∗
M
)
%
m
k
=
r
2
(r_1+t*M) \%m_k=r_2
(r1+t∗M)%mk=r2,即可满足第
k
k
k个方程。那么合并后前
k
k
k个同余方程的通解就是
x
=
r
1
+
t
∗
M
+
i
∗
l
c
m
(
M
,
m
k
)
,
i
∈
Z
x = r_1 + t*M + i* lcm(M,m_k), \ i \in Z
x=r1+t∗M+i∗lcm(M,mk), i∈Z
再对通解模l
c
m
(
M
,
m
k
)
lcm(M,m_k)
lcm(M,mk) 即可得到新的
a
n
s
ans
ans作为前
k
k
k个同余方程的最小整数解。
其中找
t
t
t的过程:
M
∗
t
+
m
k
∗
y
=
r
2
−
r
1
M*t + m_k*y=r_2-r_1
M∗t+mk∗y=r2−r1,其中
M
M
M就是裴蜀等式的
a
,
t
a,t
a,t就是裴蜀等式的
x
x
x,其中
r
2
−
r
1
r_2-r_1
r2−r1要满足
g
c
d
(
M
,
m
k
)
∣
(
r
2
−
r
1
)
gcd(M,m_k)|(r_2-r_1)
gcd(M,mk)∣(r2−r1),否则无解。
我们先用扩展欧几里得求解出
M
∗
t
+
m
k
∗
y
=
g
c
d
(
M
,
m
k
)
M*t + m_k*y=gcd(M,m_k)
M∗t+mk∗y=gcd(M,mk),顺便求出
g
c
d
(
M
,
m
k
)
gcd(M,m_k)
gcd(M,mk),再将得到的解
t
=
t
∗
r
2
−
r
1
g
c
d
(
M
,
m
k
)
t = t* \frac{r_2-r_1}{gcd(M,m_k)}
t=t∗gcd(M,mk)r2−r1,即可求得
t
t
t。
4、组合数
方法一:利用递推公式:
c
[
a
]
[
b
]
=
c
[
a
−
1
]
[
b
]
+
c
[
a
−
1
]
[
b
−
1
]
c[a][b] = c[a-1][b]+c[a-1][b-1]
c[a][b]=c[a−1][b]+c[a−1][b−1]即考虑当前选不选的问题。
O
(
n
2
)
O(n^2)
O(n2)其中(
n
≤
2000
n \le 2000
n≤2000)
方法二:预处理逆元法:根据公式计算:
C
a
b
=
a
!
(
a
−
b
)
!
b
!
C_a^{b} = \frac{a!}{(a-b)!b!}
Cab=(a−b)!b!a! 由于后面数值一般很大会设置一个模数,可以考虑计算出
f
a
c
[
i
]
fac[i]
fac[i]表示
i
i
i的阶乘,
i
n
f
a
c
[
i
]
infac[i]
infac[i]表示
i
i
i的阶乘的逆元。因此:
C
a
b
=
f
a
c
[
a
]
∗
i
n
f
a
c
[
a
−
b
]
%
p
∗
i
n
f
a
c
[
b
]
%
p
C_a^{b}=fac[a]*infac[a-b]\%p*infac[b]\%p
Cab=fac[a]∗infac[a−b]%p∗infac[b]%p.此方法可以预处理出$n \le 1e5 $的数。
方法三:利用
L
u
c
a
s
Lucas
Lucas定理:
C
a
b
=
C
a
%
p
b
%
p
∗
C
a
/
/
p
b
/
/
p
(
m
o
d
p
)
C_a^{b}=C_{a\%p}^{b\%p}*C_{a//p}^{b//p}\ (mod \ p)
Cab=Ca%pb%p∗Ca//pb//p (mod p)可以处理(
1
≤
b
≤
a
≤
1
0
18
1 \le b \le a \le10^{18}
1≤b≤a≤1018,
p
p
p为质数)
def lucas(a,b,p): if a<p and b<p:return C(a,b,p) return C(a%p,b%p,p)*lucas(a//p,b//p,p)%p
- 应用:括号序列(
C
2
n
n
−
C
2
n
n
−
1
C_{2n}^{n}-C_{2n}^{n-1}
- 卡特兰数公式:
f
(
n
)
=
C
2
n
n
n
+
1
=
C
2
n
n
−
C
2
n
n
−
1
f(n)=\frac{C_{2n}^{n}}{n+1}=C_{2n}^{n}-C_{2n}^{n-1}
- 卡特兰数公式:
- 应用:括号序列(
5、容斥原理
二项式反演:
恰好和至少的转换(常用到)
- 设
f
i
f_i
k
k
g
i
g_i
k
k
f
k
=
∑
i
=
k
n
(
n
k
)
g
i
f_k=\sum_{i=k}^{n} \binom{n}{k}g_i
fk=i=k∑n(kn)gi
- 根据二项式反演则有:
g
k
=
∑
i
=
k
n
(
−
1
)
i
−
k
(
i
k
)
f
i
g_k=\sum_{i=k}^{n}(-1)^{i-k} \binom{i}{k}f_i
gk=i=k∑n(−1)i−k(ki)fi
- 当我们需要求恰好
k
k
k
k
- 设
恰好和至多的转换(没上面常用)
- 设
f
i
f_i
k
k
g
i
g_i
k
k
f
k
=
∑
i
=
0
n
(
n
k
)
g
i
f_k=\sum_{i=0}^{n} \binom{n}{k}g_i
fk=i=0∑n(kn)gi
- 根据二项式反演则有:
g
k
=
∑
i
=
0
n
(
−
1
)
k
−
i
(
i
k
)
f
i
g_k=\sum_{i=0}^{n} (-1)^{k-i} \binom{i}{k}f_i
gk=i=0∑n(−1)k−i(ki)fi
- 当发现最多有
k
k
- 设
6、博弈论
四种经典组合游戏
- 尼姆游戏:
n
n
a
i
a_i
- 结论:令$S=\oplus_{i=1}^n a_i
先手必胜当且仅当
先手必胜当且仅当
ot =0$.(根据异或性质容易判断)
- 结论:令$S=\oplus_{i=1}^n a_i
- 巴什博弈:
1
1
n
n
- 结论:可以发现不管怎么取都可以操作出
m
+
1
m+1
(
m
+
1
)
∣
n
(m+1)|n
- 结论:可以发现不管怎么取都可以操作出
- 威佐夫博弈:
2
2
- 结论:设
x
=
1
+
5
2
x=\frac{1+\sqrt 5}{2}
i
i
a
i
,
b
i
a_i,b_i
,
,
- 在实际代码中就是
m
i
n
(
a
,
b
)
=
i
n
t
(
a
b
s
(
a
−
b
)
∗
1
+
5
2
)
min(a,b)= int(abs(a-b)*\frac{1+\sqrt 5}{2})
w
i
n
win
- 结论:设
- 斐波那契博弈:
1
1
n
n
- 结论:当且仅当石子个数为斐波那契数时先手必败。
- 尼姆游戏:
N
i
m
−
S
G
Nim-SG
Nim−SG函数
尼姆游戏的变种总结出来的规律。
M
e
x
Mex
Mex运算:
m
e
x
(
S
)
=
min
{
x
∈
N
∣
x
∉
S
}
{
x
}
mex(S)=\min\limits_{\{x \in \mathbb{N} \mid x
ot \in S \}} \{x\}mex(S)={x∈N∣x∈S}min{x}也就是不在
S
S
S集合中的最小自然数
S
G
SG
SG函数计算每一个节点的
s
g
sg
sg值,
S
G
(
x
)
=
m
e
x
(
{
S
G
(
y
1
)
,
S
G
(
y
2
)
,
…
,
S
G
(
y
k
)
}
)
SG(x)=mex(\{SG(y_1),SG(y_2),\dots,SG(y_k)\})
SG(x)=mex({SG(y1),SG(y2),…,SG(yk)}),其中
y
1
,
y
2
,
…
,
y
k
y_1,y_2,\dots,y_k
y1,y2,…,yk是
x
x
x的后继节点。
def mex(lst): lst = list(set(lst)) return next((idx for idx,num in enumerate(lst) if idx!=num),lst[-1]+1) def SG(lst,n): sg = [0]*(n+5) for i in range(1,n+1): sg[i] = mex([sg[i-j] for j in lst if i-j>=0]) return sg
这个模板基本通用了。