前言
近来发现自己的数论知识需要进行补充,感觉自己相对别人落下了好多,所以打算写一篇博客,跟进一下自己的知识储备
正文
1.数论函数
数论函数,指定义域为正整数、陪域为复数的函数
f
:
Z
+
→
C
f:\mathbb{Z^+}\rightarrow\mathbb{C}
f:Z+→C
- Tip:常数函数也是数论函数
我们通常用一个数字代表常数函数,比如 1 1 1代表 f ( n ) = 1 f(n)=1 f(n)=1, x x x代表 f ( n ) = x f(n)=x f(n)=x
2.加性函数
对于一个函数 f f f,如果对于 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1满足 f ( a b ) = f ( a ) + f ( b ) f(ab)=f(a)+f(b) f(ab)=f(a)+f(b),就称其为加性函数
3.常见加性函数
- 质因子数
ω ( n ) = ∑ p ∣ n 1 \omega(n)=\sum_{p|n}1 ω(n)=p∣n∑1
p p p为质数
g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1说明 a , b a,b a,b没有相同的质因子,所以这是加性函数 - 质因子之和
a 1 ( n ) = ∑ p ∣ n p a_1(n)=\sum_{p|n}p a1(n)=p∣n∑p
p p p为质数
证明同“相异质因子数”的证明
4.完全加性函数
对于一个函数 f f f,如果 ∀ a , b \forall a,b ∀a,b满足 f ( a b ) = f ( a ) + f ( b ) f(ab)=f(a)+f(b) f(ab)=f(a)+f(b),就称其为完全加性函数
5.常见完全加性函数
- 可相同质因子数
Ω ( n ) = ∑ p ∣ n t \Omega(n)=\sum_{p|n}t Ω(n)=p∣n∑t
p p p为质数, t t t为最大的整数满足 p t ∣ n p^t|n pt∣n
两数相乘,质因子数量可以直接合并 - 可相同质因子之和
a 0 ( n ) = ∑ p ∣ n p ∗ t a_0(n)=\sum_{p|n}p*t a0(n)=p∣n∑p∗t
p p p为质数, t t t为最大的整数满足 p t ∣ n p^t|n pt∣n
证明同“可相同质因子数”的证明
6.积性函数
对于一个函数 f f f,如果 f ( 1 ) = 1 f(1)=1 f(1)=1,且对于 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1满足 f ( a b ) = f ( a ) ∗ f ( b ) f(ab)=f(a)*f(b) f(ab)=f(a)∗f(b),就称其为积性函数
- Tip:注意一定要满足
f
(
1
)
=
1
f(1)=1
f(1)=1,这个条件把函数
f
(
x
)
=
0
f(x)=0
f(x)=0这个函数排除了
证明:
∵ f ( a ) = f ( a ) ∗ f ( 1 ) \because f(a)=f(a)*f(1) ∵f(a)=f(a)∗f(1)
∴ f ( a ) ∗ ( f ( 1 ) − 1 ) = 0 \therefore f(a)*(f(1)-1)=0 ∴f(a)∗(f(1)−1)=0
∴ f ( 1 ) = 1 或 f ( a ) = 0 \therefore f(1)=1或f(a)=0 ∴f(1)=1或f(a)=0
7.常见积性函数
- Euler’s totient function(欧拉函数)
φ ( n ) \varphi(n) φ(n)表示 [ 1 , n ] [1,n] [1,n]中与 n n n互质的数个数
φ ( n ) = n ∗ ∏ i = 1 k ( 1 − 1 p i ) \varphi(n)=n*\prod_{i=1}^{k}\left(1-\frac{1}{p_i}\right) φ(n)=n∗i=1∏k(1−pi1)
其中 p 1 , p 2 … … p k p_1, p_2……p_k p1,p2……pk为 n n n的所有质因数
容易发现每个质因数 p p p对 φ ( n ) \varphi(n) φ(n)的贡献都是独立的,设 t t t为最大的整数满足 p t ∣ n p^t|n pt∣n,其贡献的乘积为: ( p − 1 ) ∗ p t − 1 (p-1)*p^{t-1} (p−1)∗pt−1
所以 φ ( n ) \varphi(n) φ(n)是积性函数 - Möbius function(莫比乌斯函数)
μ ( n ) = { 1 , 若 n = 1 ( − 1 ) k , 若 n 无 平 方 数 因 数 且 n = p 1 ∗ p 2 ⋅ ⋅ ⋅ p k 0 , 若 n 有 平 方 数 因 数 \mu(n)=\begin{cases} 1,\ \ \ \ \ \ \ \ 若n=1 \\ (-1)^k,若n无平方数因数且n=p_1*p_2···p_k\\ 0,\ \ \ \ \ \ \ \ 若n有平方数因数 \end{cases} μ(n)=⎩⎪⎨⎪⎧1, 若n=1(−1)k,若n无平方数因数且n=p1∗p2⋅⋅⋅pk0, 若n有平方数因数
这是一个比较清楚的定义,容易发现每个质因数 p p p对 μ ( n ) \mu(n) μ(n)的贡献都是独立的,设 t t t为最大的整数满足 p t ∣ n p^t|n pt∣n,其贡献的乘积为: { − 1 , 若 t = 1 0 , 若 t > 1 \begin{cases}-1,若t=1\\ 0,\ \ \ 若t>1 \end{cases} {−1,若t=10, 若t>1
所以 μ ( n ) \mu(n) μ(n)是积性函数 - divisor function(除数函数)
σ x ( n ) = ∑ d ∣ n d x \sigma_x(n)=\sum_{d|n}d^x σx(n)=d∣n∑dx
这个积性函数的证明也非常简单,每加入一个质因数 p p p对 σ x ( n ) \sigma_x(n) σx(n)的贡献都是使值乘上一个定值,设 t t t为最大的整数满足 p t ∣ n p^t|n pt∣n,其贡献的乘积为 ∑ i = 0 t p x i \sum_{i=0}^tp^{xi} i=0∑tpxi
所以除数函数还有一个式子是
σ x ( n ) = ∏ p ∑ p j ∣ n p x j \sigma_x(n)=\prod_{p}\sum_{p^j|n}p^{xj} σx(n)=p∏pj∣n∑pxj
p p p为质数
特殊的, σ x ( n ) \sigma_x(n) σx(n)有两个值得注意的情况
σ 0 ( n ) \sigma_0(n) σ0(n)代表 n n n的因数数量,也写作 d ( n ) d(n) d(n)
σ 1 ( n ) \sigma_1(n) σ1(n)代表 n n n的因数之和,也写作 σ ( n ) \sigma(n) σ(n)
8.完全积性函数
对于一个函数 f f f,如果 f ( 1 ) = 1 f(1)=1 f(1)=1, ∀ a , b \forall a,b ∀a,b满足 f ( a b ) = f ( a ) ∗ f ( b ) f(ab)=f(a)*f(b) f(ab)=f(a)∗f(b),就称其为完全积性函数
9.常见完全积性函数
- power function(幂函数)
I d k ( n ) = n k Id_k(n)=n^k Idk(n)=nk
证明很容易 I d k ( a ) ∗ I d k ( b ) = a k ∗ b k = ( a ∗ b ) k = I d k ( a ∗ b ) Id_k(a)*Id_k(b)=a^k*b^k=(a*b)^k=Id_k(a*b) Idk(a)∗Idk(b)=ak∗bk=(a∗b)k=Idk(a∗b)
特殊的, I d k ( n ) Id_k(n) Idk(n)有两个值得注意的情况
I d 0 ( n ) = 1 Id_0(n)=1 Id0(n)=1,也写作 1 ( n ) 1(n) 1(n)或者是 I ( n ) I(n) I(n)
I d 1 ( n ) = n Id_1(n)=n Id1(n)=n,也写作 I d ( n ) Id(n) Id(n) - Liouville function(刘维尔函数)
λ ( n ) = ( − 1 ) Ω ( n ) \lambda(n)=(-1)^{\Omega(n)} λ(n)=(−1)Ω(n)
Ω ( n ) \Omega(n) Ω(n)是完全加性函数,所以 λ ( n ) \lambda(n) λ(n)是完全积性函数 - 单位函数
ϵ ( n ) = { 1 , n = 1 0 , n > 1 \epsilon(n)=\begin{cases}1,n=1\\0,n>1 \end{cases} ϵ(n)={1,n=10,n>1
特殊的, ϵ ( n ) \epsilon(n) ϵ(n)有时也写作 e ( n ) e(n) e(n)
显然是完全积性函数
Dirichlet product(狄利克雷卷积)
两个数论函数
f
,
g
f,g
f,g,他们的狄利克雷卷积为
(
f
∗
g
)
(
n
)
=
∑
d
∣
n
f
(
d
)
∗
g
(
n
d
)
(f*g)(n)=\sum_{d|n}f(d)*g(\frac nd)
(f∗g)(n)=d∣n∑f(d)∗g(dn)
相关性质:
- 交换律:
f
∗
g
=
g
∗
f
f ∗ g = g ∗ f
f∗g=g∗f
根据定义式可得 - 结合律:
(
f
∗
g
)
∗
h
=
f
∗
(
g
∗
h
)
(f ∗ g) ∗ h = f ∗ (g ∗ h)
(f∗g)∗h=f∗(g∗h)
展开
( ( f ∗ g ) ∗ h ) ( n ) = ∑ d ∣ n ( f ∗ g ) ( d ) ∗ h ( n d ) = ∑ d ∣ n ( ∑ k ∣ d f ( k ) ∗ g ( d k ) ) ∗ h ( n d ) = ∑ a ∗ b ∗ c = n f ( a ) ∗ g ( b ) ∗ h ( c ) \begin{aligned} ((f*g)*h)(n)&=\sum_{d|n}(f*g)(d)*h(\frac nd)\\ &=\sum_{d|n}(\sum_{k|d}f(k)*g(\frac dk))*h(\frac nd)\\ &=\sum_{a*b*c=n}f(a)*g(b)*h(c)\\ \end{aligned} ((f∗g)∗h)(n)=d∣n∑(f∗g)(d)∗h(dn)=d∣n∑(k∣d∑f(k)∗g(kd))∗h(dn)=a∗b∗c=n∑f(a)∗g(b)∗h(c)
同理 ( f ∗ ( g ∗ h ) ) ( n ) = ( ( g ∗ h ) ∗ f ) ( n ) = ∑ a ∗ b ∗ c = n g ( a ) ∗ h ( b ) ∗ f ( c ) (f ∗ (g ∗ h))(n)=((g*h)*f)(n)=\sum_{a*b*c=n}g(a)*h(b)*f(c) (f∗(g∗h))(n)=((g∗h)∗f)(n)=a∗b∗c=n∑g(a)∗h(b)∗f(c)
故 ( f ∗ g ) ∗ h = f ∗ ( g ∗ h ) (f ∗ g) ∗ h = f ∗ (g ∗ h) (f∗g)∗h=f∗(g∗h) - 分配律:
f
∗
(
g
+
h
)
=
f
∗
g
+
f
∗
h
f ∗ (g + h) = f ∗ g + f ∗ h
f∗(g+h)=f∗g+f∗h
证明:
( ( g + h ) ∗ f ) ( n ) = ∑ d ∣ n ( g ( d ) + h ( d ) ) ∗ f ( n d ) = ∑ d ∣ n g ( d ) ∗ f ( n d ) + ∑ d ∣ n h ( d ) ∗ f ( n d ) = ( f ∗ g ) ( n ) + ( f ∗ h ) ( n ) = ( f ∗ g + f ∗ h ) ( n ) \begin{aligned} ((g+h)*f)(n)&=\sum_{d|n}(g(d)+h(d))*f(\frac nd)\\ &=\sum_{d|n}g(d)*f(\frac nd)+\sum_{d|n}h(d)*f(\frac nd)\\ &= (f ∗ g)(n) + (f ∗ h)(n)\\ &= (f ∗ g+ f ∗ h)(n)\\ \end{aligned} ((g+h)∗f)(n)=d∣n∑(g(d)+h(d))∗f(dn)=d∣n∑g(d)∗f(dn)+d∣n∑h(d)∗f(dn)=(f∗g)(n)+(f∗h)(n)=(f∗g+f∗h)(n) - 单位元
f
∗
ϵ
=
f
f*\epsilon=f
f∗ϵ=f
显然 - 若
f
,
g
f,g
f,g为积性函数,则
f
∗
g
f*g
f∗g为积性函数,若
f
,
g
f,g
f,g为完全积性函数,则
f
∗
g
f*g
f∗g为完全积性函数
证明:设 F = f ∗ g F=f*g F=f∗g,要证的是 F ( i j ) = F ( i ) ∗ F ( j ) F(ij)=F(i)*F(j) F(ij)=F(i)∗F(j)
F ( i j ) = ∑ a b = i j f ( a ) ∗ g ( b ) F(ij)=\sum_{ab=ij}f(a)*g(b) F(ij)=ab=ij∑f(a)∗g(b)
F ( i ) ∗ F ( j ) = ( ∑ a 0 b 0 = i f ( a 0 ) ∗ g ( b 0 ) ) ∗ ( ∑ a 1 b 1 = j f ( a 1 ) ∗ g ( b 1 ) ) = ∑ a 0 a 1 b 0 b 1 = i j ( f ( a 0 ) ∗ f ( a 1 ) ) ∗ ( g ( b 0 ) ∗ g ( b 1 ) ) = ∑ a 0 a 1 b 0 b 1 = i j f ( a 0 a 1 ) ∗ g ( b 0 b 1 ) = F ( i j ) \begin{aligned} F(i)*F(j)&=\left(\sum_{a_0b_0=i}f(a_0)*g(b_0)\right)*\left(\sum_{a_1b_1=j}f(a_1)*g(b_1)\right)\\ &=\sum_{a_0a_1b_0b_1=ij}(f(a_0)*f(a_1))*(g(b_0)*g(b_1))\\ &=\sum_{a_0a_1b_0b_1=ij}f(a_0a_1)*g(b_0b_1)\\ &=F(ij) \end{aligned} F(i)∗F(j)=(a0b0=i∑f(a0)∗g(b0))∗⎝⎛a1b1=j∑f(a1)∗g(b1)⎠⎞=a0a1b0b1=ij∑(f(a0)∗f(a1))∗(g(b0)∗g(b1))=a0a1b0b1=ij∑f(a0a1)∗g(b0b1)=F(ij)
常见的狄利克雷卷积式子
-
d
=
1
∗
1
d=1*1
d=1∗1
d ( n ) = ∑ d ∣ n 1 d(n)=\sum_{d|n}1 d(n)=d∣n∑1 -
σ
=
I
d
∗
1
\sigma=Id*1
σ=Id∗1
σ ( n ) = ∑ d ∣ n d \sigma(n)=\sum_{d|n}d σ(n)=d∣n∑d -
ϵ
=
μ
∗
1
\epsilon=\mu*1
ϵ=μ∗1
ϵ ( n ) = ∑ d ∣ n μ ( d ) \epsilon(n)=\sum_{d|n}\mu(d) ϵ(n)=d∣n∑μ(d)
证明:
设 n n n有 k k k个相异质因子
若 k = 0 k=0 k=0,那么结果为 1 1 1
否则 ∑ d ∣ n μ ( d ) = ∑ i = 0 k ( − 1 ) i ( k i ) = ( 1 − 1 ) k = 0 \begin{aligned} \sum_{d|n}\mu(d)&=\sum_{i=0}^k(-1)^i\dbinom{k}{i}\\ &=(1-1)^k\\ &=0 \end{aligned} d∣n∑μ(d)=i=0∑k(−1)i(ik)=(1−1)k=0 -
φ
=
μ
∗
I
d
\varphi=\mu*Id
φ=μ∗Id
φ ( n ) = ∑ d ∣ n μ ( d ) n d \varphi(n)=\sum_{d|n}\mu(d)\frac nd φ(n)=d∣n∑μ(d)dn
证明:
首先证明: φ ∗ 1 = I d \varphi*1=Id φ∗1=Id
即
∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi(d)=n d∣n∑φ(d)=n
yangxin2003的形象证明
给定一个 n n n,枚举 1 n , 2 n ⋅ ⋅ ⋅ n n \frac 1n,\frac 2n···\frac nn n1,n2⋅⋅⋅nn,并将每个约分
考虑枚举约分后的分母(即枚举 d d d), φ ( d ) \varphi(d) φ(d)即为 d d d为分母时的最简分数数量,对应上面的 n n n个数
证完之后然后莫比乌斯反演(下面会提到)即可
Möbius inversion formula(莫比乌斯反演)
f
=
g
∗
1
⇔
g
=
u
∗
f
f=g*1\Leftrightarrow g=u*f
f=g∗1⇔g=u∗f
另一种表示方式:
如果多项式
f
,
g
f,g
f,g满足
f
(
n
)
=
∑
d
∣
n
g
(
d
)
f(n)=\sum_{d|n}g(d)
f(n)=d∣n∑g(d)
那么也一定满足
g
(
n
)
=
∑
d
∣
n
μ
(
d
)
f
(
n
d
)
g(n)=\sum_{d|n}\mu(d)f(\frac nd)
g(n)=d∣n∑μ(d)f(dn)
反之也成立
证明:
设
f
=
g
∗
1
f=g*1
f=g∗1
两边卷上
μ
\mu
μ
μ
∗
f
=
μ
∗
g
∗
1
\mu*f=\mu*g*1
μ∗f=μ∗g∗1
整理
μ
∗
f
=
ϵ
∗
g
=
g
\mu*f=\epsilon*g=g
μ∗f=ϵ∗g=g
即
g
=
μ
∗
f
g=\mu*f
g=μ∗f
反过来同理
欧拉筛
每个数都只会被其最小的质因数筛到
复杂度
Θ
(
n
)
\Theta(n)
Θ(n),适合筛各种积性函数
inline void getlist(const int listsize)
{
memset(isprime,1,sizeof(isprime));
isprime[1]=0;
for(rg int i=2;i<=listsize;i++)
{
if(isprime[i]==1)prime[++primesize]=i;
for(int j=1;j<=primesize&&(LL)i*(LL)prime[j]<=(LL)listsize;j++)
{
isprime[i*prime[j]]=0;
if(i%prime[j]==0)break;
}
}
}
- Tip:对于欧拉筛有一个小技巧,可以开桶记录每个数的最小质因子,那么就可以做到 Θ ( n ) \Theta(n) Θ(n)预处理,单次 Θ ( l o g n ) \Theta(logn) Θ(logn)的质因数分解复杂度了
- Tip:单次的分解质因数复杂度是 Θ ( n ) \Theta(\sqrt n) Θ(n)的,枚举小于 n \sqrt n n的数,如果整除就除掉,如果最后剩下的值不为1,那么剩下的这个值也是一个质因数,次数为1
杜教筛
现在有个数论函数
f
(
n
)
f(n)
f(n),现在要求
S
(
n
)
=
∑
i
=
1
n
f
(
i
)
S(n)=\sum_{i=1}^nf(i)
S(n)=∑i=1nf(i)
杜教筛的核心思想是:找到一个数论函数
g
(
n
)
g(n)
g(n)
因为显然满足
∑
i
=
1
n
∑
d
∣
i
f
(
d
)
g
(
i
d
)
=
∑
i
=
1
n
g
(
i
)
S
(
⌊
n
i
⌋
)
\sum_{i=1}^n\sum_{d|i}f(d)g(\frac id)=\sum_{i=1}^ng(i)S(\left\lfloor \frac ni\right\rfloor)
i=1∑nd∣i∑f(d)g(di)=i=1∑ng(i)S(⌊in⌋)
所以就有
S
(
n
)
S(n)
S(n)的递推式:
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
(
f
∗
g
)
(
i
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\left\lfloor \frac ni\right\rfloor)
g(1)S(n)=i=1∑n(f∗g)(i)−i=2∑ng(i)S(⌊in⌋)
- Tip:能用杜教筛的前提是找到了合适的 g ( n ) g(n) g(n),杜教筛能够筛某几种特定的积性函数,在下面会分别列举
常见杜教筛板子
- 求
φ
(
n
)
的
前
缀
和
S
(
n
)
\varphi(n)的前缀和S(n)
φ(n)的前缀和S(n)
我们已经知道 φ ∗ 1 = I d \varphi*1=Id φ∗1=Id
那么在 f = φ f=\varphi f=φ的条件下, g = 1 g=1 g=1无疑是最佳选择,
那么,上面的递推式就变成了
S ( n ) = ∑ i = 1 n i − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n)=\sum_{i=1}^ni-\sum_{i=2}^nS(\left\lfloor \frac ni\right\rfloor) S(n)=i=1∑ni−i=2∑nS(⌊in⌋)
首先证明这个递推式里的元素数量是 Θ ( n ) \Theta(\sqrt n) Θ(n)的
解释:
∵ ⌊ ⌊ x a ⌋ b ⌋ = ⌊ x a b ⌋ ∴ 所 有 被 访 问 的 元 素 为 ⌊ n i ⌋ 元 素 数 是 Θ ( n ) 的 设 m = n 这 些 元 素 是 1 , 2 ⋅ ⋅ ⋅ , m − 1 , m , ⌊ n m ⌋ , ⌊ n m − 1 ⌋ ⋅ ⋅ ⋅ , ⌊ n 2 ⌋ , ⌊ n 1 ⌋ \because\left\lfloor\frac {\left\lfloor\frac xa\right\rfloor}b \right\rfloor=\left\lfloor\frac x{ab} \right\rfloor\\ \therefore所有被访问的元素为\left\lfloor\frac ni \right\rfloor\\ 元素数是\Theta(\sqrt n)的\\ 设m=\sqrt n\\ 这些元素是1,2···,m-1,m,\left\lfloor\frac nm\right\rfloor,\left\lfloor\frac n{m-1}\right\rfloor···,\left\lfloor\frac n2\right\rfloor,\left\lfloor\frac n1\right\rfloor ∵⌊b⌊ax⌋⌋=⌊abx⌋∴所有被访问的元素为⌊in⌋元素数是Θ(n)的设m=n这些元素是1,2⋅⋅⋅,m−1,m,⌊mn⌋,⌊m−1n⌋⋅⋅⋅,⌊2n⌋,⌊1n⌋
然后考虑算法复杂度
对于上面那个式子的第一项显然是 ( 1 + n ) ∗ n 2 \frac {(1+n)*n}2 2(1+n)∗n,计算是 Θ ( 1 ) 的 \Theta(1)的 Θ(1)的
对于第二项,刚才已经证明 ⌊ n i ⌋ \left\lfloor\frac ni \right\rfloor ⌊in⌋的取值只有 Θ ( n ) \Theta(\sqrt n) Θ(n)个,那么我们只要枚举每个取值,计算其贡献次数即可
复杂度的式子是
∑ i = 1 ⌊ n ⌋ Θ ( i ) + ∑ i = 1 ⌊ n ⌋ Θ ( n i ) \sum_{i=1}^{\left\lfloor \sqrt n\right\rfloor}\Theta(\sqrt i)+\sum_{i=1}^{\left\lfloor \sqrt n\right\rfloor}\Theta(\sqrt{\frac ni}) i=1∑⌊n⌋Θ(i)+i=1∑⌊n⌋Θ(in)
这个式子的结果是 Θ ( n 3 4 ) \Theta(n^{\frac 34}) Θ(n43)
由于前面的 n \sqrt n n个值可以用线性筛跑出来,所以复杂度为
n + ∑ i = 1 ⌊ n ⌋ Θ ( n i ) \sqrt n+\sum_{i=1}^{\left\lfloor \sqrt n\right\rfloor}\Theta(\sqrt{\frac ni}) n+i=1∑⌊n⌋Θ(in)
瓶颈在后一半,所以可以通过调整块大小来优化复杂度
设我们筛前 k k k个,那么前面一项的复杂度为 Θ ( k ) \Theta(k) Θ(k),后面一项的复杂度为 Θ ( n k ) \Theta(\frac n{\sqrt k}) Θ(kn)(这个的复杂度证明是根据微积分可得 ∑ i = 1 n Θ ( 1 i ) = Θ ( n ) \sum_{i=1}^n\Theta(\frac 1{\sqrt i})=\Theta(\sqrt n) ∑i=1nΘ(i1)=Θ(n),然后带入得 Θ ( n ) ∗ Θ ( n k ) = Θ ( n k ) \Theta(\sqrt n)*\Theta(\sqrt {\frac nk})=\Theta(\frac n{\sqrt k}) Θ(n)∗Θ(kn)=Θ(kn)),总复杂度最优时
k = n k , k 3 2 = n , k = n 2 3 k=\frac n{\sqrt k},k^{\frac 32}=n,k=n^{\frac 23} k=kn,k23=n,k=n32
最优复杂度为 Θ ( n 2 3 ) \Theta(n^{\frac 23}) Θ(n32)
代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
namespace fast_IO
{
const int IN_LEN=10000000,OUT_LEN=10000000;
char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
//#define getchar() getchar_()
//#define putchar(x) putchar_((x))
//#include<ctime>
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
//template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
char cu=getchar();x=0;bool fla=0;
while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
if(x>=10)printe(x/10);
putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
if(x<0)putchar('-'),printe(-x);
else printe(x);
}
const int MAX=2000000;
bool isprime[MAX+1];
int n,prime[MAX+1],primesize;LL phi[MAX+1],phi1[MAX+1];
inline void getlist(const LL listsize)
{
memset(isprime,1,sizeof(isprime));
isprime[1]=0,phi[1]=1;;
for(rg int i=2;i<=listsize;i++)
{
if(isprime[i])prime[++primesize]=i,phi[i]=i-1;
for(rg int j=1;j<=primesize&&(LL)i*prime[j]<=listsize;j++)
{
isprime[i*prime[j]]=0;
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
inline LL Val(const int x)
{
if(x<=MAX)return phi[x];
return phi1[n/x];
}
int main()
{
getlist(MAX);
for(rg int i=1;i<=MAX;i++)phi[i]+=phi[i-1];
read(n);
for(rg int i=min((int)sqrt(n),n/(MAX+1));i>=1;i--)
{
const int u=n/i;
LL res=(LL)u*(u+1)/2;
int limit=sqrt(u);
for(rg int j=1;j<=limit;j++)res-=Val(u/j);
limit++;
for(rg int j=1;limit*j<=u;j++)res-=phi[j]*((u/j)-(u/(j+1)));
phi1[i]=res;
}
print(Val(n));
return flush(),0;
}
- 求
μ
(
n
)
\mu(n)
μ(n)的前缀和
S
(
n
)
S(n)
S(n)
同样的,我们可以找到一个 g ( n ) g(n) g(n),没错又是 1 1 1,因为 μ ∗ 1 = ϵ \mu*1=\epsilon μ∗1=ϵ
所以带入式子 S ( n ) = 1 − ∑ i = 2 n S ( ⌊ n i ⌋ ) S(n)=1-\sum_{i=2}^nS(\left\lfloor \frac ni\right\rfloor) S(n)=1−i=2∑nS(⌊in⌋)
哇,这不是东西更少了吗,和上面一样的思路,复杂度 Θ ( n 2 3 ) \Theta(n^{\frac 23}) Θ(n32)
代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<cmath>
namespace fast_IO
{
const int IN_LEN=10000000,OUT_LEN=10000000;
char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
//#define getchar() getchar_()
//#define putchar(x) putchar_((x))
//#include<ctime>
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
//template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
char cu=getchar();x=0;bool fla=0;
while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
if(x>=10)printe(x/10);
putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
if(x<0)putchar('-'),printe(-x);
else printe(x);
}
const int MAX=2000000;
bool isprime[MAX+1];
int T,n;
int prime[MAX+1],primesize;LL mu[MAX+1],mu1[MAX+1];
inline void getlist(const LL listsize)
{
memset(isprime,1,sizeof(isprime));
isprime[1]=0,mu[1]=1;
for(rg int i=2;i<=listsize;i++)
{
if(isprime[i])prime[++primesize]=i,mu[i]=-1;
for(rg int j=1;j<=primesize&&(LL)i*prime[j]<=listsize;j++)
{
isprime[i*prime[j]]=0;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
}
inline LL Val(const int x)
{
if(x<=MAX)return mu[x];
return mu1[n/x];
}
int main()
{
getlist(MAX);
for(rg int i=1;i<=MAX;i++)mu[i]+=mu[i-1];
read(n);
for(rg int i=min((int)sqrt(n),n/(MAX+1));i>=1;i--)
{
const int u=n/i;
LL res=1;
int limit=sqrt(u);
for(rg int j=1;j<=limit;j++)res-=Val(u/j);
limit++;
for(rg int j=1;limit*j<=u;j++)res-=mu[j]*((u/j)-(u/(j+1)));
mu1[i]=res;
}
print(Val(n));
return flush(),0;
}
其实代码差不太多
Min25筛
内容太多辣,可以看我另一篇博客Min_25筛学习Tip+链接
也是做积性函数前缀和的,并且能使得很多题目得到简化
我是分割线,目前要写的内容就这么多了,想到再更