数论函数学习笔记
由多个博客学习组合而成
狄利克雷卷积
所谓的狄利克雷卷积,是定义在数论函数 ( Z + → C 的函数 ) (\Z^+\rightarrow C的函数) (Z+→C的函数)间的一种二元运算,可这样定义:
( f ∗ g ) ( n ) : = ∑ x y = n f ( x ) g ( y ) (f*g)(n):=\sum_{xy=n}f(x)g(y) (f∗g)(n):=∑xy=nf(x)g(y)
也可以写成:
( f ∗ g ) ( n ) : = ∑ d ∣ n f ( d ) g ( n d ) (f*g)(n):=\sum_{d|n}f(d)g(\frac{n}{d}) (f∗g)(n):=∑d∣nf(d)g(dn)
为了方便讨论先定义一些常用的数论函数符号:
-
单位函数 ε ( n ) : = { 1 , w h i l e n = 1 0 , o t h e r w i s e \varepsilon(n):=\begin{cases} 1, \ while\ n = 1\\0,\ otherwise\end{cases} ε(n):={1, while n=10, otherwise
-
幂函数 I d k ( n ) : = n k Id_k(n):=n^k Idk(n):=nk.当 k = 1 k = 1 k=1时为恒等函数 I d ( n ) Id(n) Id(n),当 k = 0 k = 0 k=0时为常数函数 1 ( n ) 1(n) 1(n)
-
除数函数 σ k ( n ) : = ∑ d ∣ n d k \sigma_k(n):=\sum_{d|n}d^k σk(n):=∑d∣ndk,当 k = 1 k=1 k=1是为因数和函数 σ ( n ) \sigma(n) σ(n),当 k = 0 k=0 k=0时为因数个数函数 σ 0 ( n ) \sigma_{0}(n) σ0(n)
-
欧拉函数 φ ( n ) \varphi(n) φ(n)
值得注意的是,这些函数都是所谓的积性函数,即满足 f ( 1 ) = 1 f(1) = 1 f(1)=1,且若a,b互质,则有 f ( a ) f ( b ) = f ( a b ) f(a)f(b)=f(ab) f(a)f(b)=f(ab).
其中前两者还是完全积性函数,它们不需要满足a,b互质的条件也符合等式
积性函数之间的狄利克雷卷积还有特殊的性质:
若 f , g f,g f,g为积性函数,那么 f ∗ g f*g f∗g也是积性函数
首先 ( f ∗ g ) ( 1 ) = f ( 1 ) ∗ g ( 1 ) = 1 (f*g)(1)=f(1)*g(1)=1 (f∗g)(1)=f(1)∗g(1)=1,设 a , b a,b a,b互质则有:
( f ∗ g ) ( a ) ⋅ ( f ∗ g ) ( b ) = ∑ d 1 ∣ a f ( d 1 ) g ( a d 1 ) ⋅ ∑ d 2 ∣ b f ( d 2 ) g ( b d 2 ) = ∑ d 1 ∣ a , d 2 ∣ b f ( d 1 ) f ( d 2 ) g ( a d 1 ) g ( b d 2 ) = ∑ d 1 ∣ a , d 2 ∣ b f ( d 1 d 2 ) g ( a b d 1 d 2 ) (f*g)(a)\cdot(f*g)(b)=\sum_{d1|a}f(d1)g(\frac{a}{d1})\cdot\sum_{d2|b}f(d2)g(\frac{b}{d2})\\ =\sum_{d1|a,d2|b}f(d1)f(d2)g(\frac{a}{d1})g(\frac{b}{d2})\\ =\sum_{d1|a,d2|b}f(d1d2)g(\frac{ab}{d1d2}) (f∗g)(a)⋅(f∗g)(b)=d1∣a∑f(d1)g(d1a)⋅d2∣b∑f(d2)g(d2b)=d1∣a,d2∣b∑f(d1)f(d2)g(d1a)g(d2b)=d1∣a,d2∣b∑f(d1d2)g(d1d2ab)
因为 a , b a,b a,b互质,所以就有了 ( f ∗ g ) ( a ) ⋅ ( f ∗ g ) ( b ) = ( f ∗ g ) ( a b ) (f*g)(a) \cdot (f*g)(b)=(f*g)(ab) (f∗g)(a)⋅(f∗g)(b)=(f∗g)(ab)该等式成立
再考虑某些数论函数之间的关系:
除数函数与幂函数
首先根据定义我们有 ( f ∗ 1 ) ( n ) = ∑ d ∣ n f ( d ) ∗ 1 ( n d ) (f*1)(n)=\sum_{d|n}f(d)*1(\frac{n}{d}) (f∗1)(n)=∑d∣nf(d)∗1(dn)
所以可以有 ( I d k ∗ 1 ) ( n ) = ∑ d ∣ n I d k ( d ) 1 ( n d ) = ∑ d ∣ n d k = σ k ( n ) (Id_k*1)(n) = \sum_{d|n}Id_k(d)1(\frac{n}{d})=\sum_{d|n}d^k=\sigma_k(n) (Idk∗1)(n)=∑d∣nIdk(d)1(dn)=∑d∣ndk=σk(n)
简写成 ( I d k ∗ 1 ) ( x ) = σ k ( x ) (Id_k*1)(x)=\sigma_k(x) (Idk∗1)(x)=σk(x)
欧拉函数与恒等函数
( φ ∗ 1 ) ( n ) = ∑ d ∣ n φ ( d ) (\varphi*1)(n)=\sum_{d|n}\varphi(d) (φ∗1)(n)=∑d∣nφ(d)
当 n = p m n=p^m n=pm时,有:
∑ d ∣ n φ ( d ) = φ ( 1 ) + ∑ i = 1 m φ ( p i ) = 1 + ∑ i = 1 m ( p i − p i − 1 ) = p m = n \sum_{d|n}\varphi(d)=\varphi(1)+\sum_{i=1}^m \varphi(p^i)=1+\sum_{i=1}^m(p^i-p^{i-1})=p^m=n ∑d∣nφ(d)=φ(1)+∑i=1mφ(pi)=1+∑i=1m(pi−pi−1)=pm=n
故 ( φ ∗ 1 ) ( p m ) = p m (\varphi * 1)(p^m)=p^m (φ∗1)(pm)=pm
现在令 n n n为任意正整数,那么 n = ∏ p m n = \prod p^m n=∏pm 又因为 ( φ ∗ 1 ) ( n ) (\varphi*1)(n) (φ∗1)(n)为积性函数,所以 ( φ ∗ 1 ) ( n ) = ∏ p m = n (\varphi * 1)(n)=\prod p^m=n (φ∗1)(n)=∏pm=n
所以有 ( φ ∗ 1 ) = I d (\varphi*1)=Id (φ∗1)=Id
下面对于一些卷积的法则进行证明:
交换律:
(
f
∗
g
)
(
n
)
=
∑
x
y
=
n
f
(
x
)
g
(
y
)
=
∑
x
y
=
n
f
(
y
)
g
(
x
)
=
(
g
∗
f
)
(
n
)
(f*g)(n)=\sum_{xy=n}f(x)g(y)\\ =\sum_{xy=n}f(y)g(x)\\ =(g*f)(n)
(f∗g)(n)=xy=n∑f(x)g(y)=xy=n∑f(y)g(x)=(g∗f)(n)
结合律:
(
f
∗
(
g
∗
h
)
)
(
n
)
=
∑
x
y
=
n
f
(
x
)
∗
(
g
∗
h
)
(
y
)
=
∑
x
y
=
n
f
(
x
)
∗
∑
u
v
=
y
g
(
u
)
∗
h
(
v
)
=
∑
x
u
v
=
n
f
(
x
)
g
(
u
)
h
(
v
)
=
∑
y
v
=
n
h
(
v
)
∗
∑
x
u
=
y
f
(
x
)
g
(
u
)
=
(
(
f
∗
g
)
∗
h
)
(
n
)
(f*(g*h))(n)=\sum_{xy=n}f(x)*(g*h)(y)\\ =\sum_{xy=n}f(x)*\sum_{uv=y}g(u)*h(v)\\ =\sum_{xuv=n}f(x)g(u)h(v)\\ =\sum_{yv=n}h(v)*\sum_{xu=y}f(x)g(u)\\ =((f*g)*h)(n)
(f∗(g∗h))(n)=xy=n∑f(x)∗(g∗h)(y)=xy=n∑f(x)∗uv=y∑g(u)∗h(v)=xuv=n∑f(x)g(u)h(v)=yv=n∑h(v)∗xu=y∑f(x)g(u)=((f∗g)∗h)(n)
分配律:
(
f
∗
(
g
+
h
)
)
(
n
)
=
∑
x
y
=
n
f
(
x
)
∗
(
g
+
h
)
(
y
)
=
∑
x
y
=
n
f
(
x
)
g
(
y
)
+
f
(
x
)
h
(
y
)
=
∑
x
y
=
n
f
(
x
)
g
(
y
)
+
∑
x
y
=
n
f
(
x
)
h
(
y
)
=
(
f
∗
g
)
(
n
)
+
(
f
∗
h
)
(
n
)
(f*(g+h))(n)=\sum_{xy=n}f(x)*(g+h)(y)\\ =\sum_{xy=n}f(x)g(y) + f(x)h(y)\\ =\sum_{xy=n}f(x)g(y) + \sum_{xy=n}f(x)h(y)\\ =(f*g)(n)+(f*h)(n)\\
(f∗(g+h))(n)=xy=n∑f(x)∗(g+h)(y)=xy=n∑f(x)g(y)+f(x)h(y)=xy=n∑f(x)g(y)+xy=n∑f(x)h(y)=(f∗g)(n)+(f∗h)(n)
单位元的用法:
(
f
∗
ε
)
(
n
)
=
∑
d
∣
n
f
(
d
)
ε
(
n
d
)
=
f
(
n
)
(f*\varepsilon)(n)=\sum_{d|n}f(d)\varepsilon(\frac{n}{d})=f(n)\\
(f∗ε)(n)=d∣n∑f(d)ε(dn)=f(n)
逆元:
若
f
∗
g
=
ε
f*g=\varepsilon
f∗g=ε时我们把
g
g
g称为
f
f
f的狄利克雷逆元并写作
f
−
1
f^{-1}
f−1
(
f
∗
f
−
1
)
=
ε
( f * f ^ {-1})=\varepsilon
(f∗f−1)=ε
莫比乌斯反演
我们定义数论函数
1
1
1的狄利克雷逆元为
μ
\mu
μ
得到
μ
(
x
)
=
{
1
n
=
1
(
−
1
)
m
n
=
p
1
p
2
.
.
.
p
m
0
o
t
h
e
r
w
i
s
e
\mu(x)=\begin{cases} 1 \ n = 1\\(-1)^m\ n = p_1p_2...p_m\\0\ otherwise\end{cases}
μ(x)=⎩
⎨
⎧1 n=1(−1)m n=p1p2...pm0 otherwise
所以有 ( f ∗ 1 ) = g (f*1)=g (f∗1)=g可推出 f = ( g ∗ μ ) f=(g * \mu) f=(g∗μ)
下面是几道经典题目的推导
P3455 [POI2007]ZAP-Queries
简要题意
求 ∑ x = 1 a ∑ y = 1 b [ g c d ( x , y ) = d ] \sum_{x=1}^{a}\sum_{y=1}^b [gcd(x,y)=d] ∑x=1a∑y=1b[gcd(x,y)=d]
推导
∑ x = 1 a ∑ y = 1 b [ g c d ( x , y ) = d ] = ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ [ g c d ( x , y ) = 1 ] = ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ ε ( g c d ( x , y ) ) = ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ ∑ k ∣ g c d ( x , y ) μ ( k ) = ∑ k = 1 n μ ( k ) ∑ x = 1 ⌊ a d k ⌋ ∑ y = 1 ⌊ b d k ⌋ 1 = ∑ k = 1 n μ ( k ) ⌊ a d k ⌋ ⌊ b d k ⌋ \sum_{x=1}^{a}\sum_{y=1}^b [gcd(x,y)=d]\\ =\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}[gcd(x,y)=1]\\ =\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\varepsilon(gcd(x,y))\\ =\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\sum_{k|gcd(x,y)}\mu(k)\\ =\sum_{k=1}^{n}\mu(k)\sum_{x=1}^{\lfloor\frac{a}{dk}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{dk}\rfloor}1\\ =\sum_{k=1}^{n}\mu(k)\lfloor\frac{a}{dk}\rfloor\lfloor\frac{b}{dk}\rfloor\\ x=1∑ay=1∑b[gcd(x,y)=d]=x=1∑⌊da⌋y=1∑⌊db⌋[gcd(x,y)=1]=x=1∑⌊da⌋y=1∑⌊db⌋ε(gcd(x,y))=x=1∑⌊da⌋y=1∑⌊db⌋k∣gcd(x,y)∑μ(k)=k=1∑nμ(k)x=1∑⌊dka⌋y=1∑⌊dkb⌋1=k=1∑nμ(k)⌊dka⌋⌊dkb⌋
其中 n = m a x ( a , b ) n=max(a,b) n=max(a,b)
推导到最后一步就可以使用整除分块加速
P2522 [HAOI2011]Problem b
简要题意
求 ∑ i = x a ∑ j = y b [ g c d ( i , j ) = d ] \sum_{i=x}^{a}\sum_{j=y}^b [gcd(i,j)=d] ∑i=xa∑j=yb[gcd(i,j)=d]
推导
这道题需要想到容斥原理。
将这个式子写成
∑
i
=
1
a
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
d
]
−
∑
i
=
1
a
∑
j
=
1
y
−
1
[
g
c
d
(
i
,
j
)
=
d
]
−
∑
i
=
1
x
−
1
∑
j
=
1
b
[
g
c
d
(
i
,
j
)
=
d
]
+
∑
i
=
1
x
−
1
∑
j
=
1
y
−
1
[
g
c
d
(
i
,
j
)
=
d
]
\sum_{i=1}^{a}\sum_{j=1}^b [gcd(i,j)=d]-\sum_{i=1}^{a}\sum_{j=1}^{y-1} [gcd(i,j)=d]-\sum_{i=1}^{x-1}\sum_{j=1}^b [gcd(i,j)=d]+\sum_{i=1}^{x-1}\sum_{j=1}^{y-1} [gcd(i,j)=d]
i=1∑aj=1∑b[gcd(i,j)=d]−i=1∑aj=1∑y−1[gcd(i,j)=d]−i=1∑x−1j=1∑b[gcd(i,j)=d]+i=1∑x−1j=1∑y−1[gcd(i,j)=d]
就跟上面那道一样了
P2257 YY的GCD
简要题意
求 ∑ x = 1 n ∑ y = 1 m [ g c d ( x , y ) = p ] \sum_{x=1}^{n}\sum_{y=1}^m [gcd(x,y)=p] ∑x=1n∑y=1m[gcd(x,y)=p]其中 p p p为任意质数
推导
首先这里筛出质数后称作
p
r
i
m
e
prime
prime数量为
t
o
t
tot
tot
∑
x
=
1
n
∑
y
=
1
m
[
g
c
d
(
x
,
y
)
=
p
]
=
∑
i
=
1
t
o
t
∑
x
=
1
n
∑
y
=
1
m
[
g
c
d
(
x
,
y
)
=
p
r
i
m
e
[
i
]
]
=
∑
i
=
1
t
o
t
∑
x
=
1
⌊
n
p
r
i
m
e
[
i
]
⌋
∑
y
=
1
⌊
m
p
r
i
m
e
[
i
]
⌋
[
g
c
d
(
x
,
y
)
=
1
]
=
∑
i
=
1
t
o
t
∑
d
=
1
m
a
x
(
n
,
m
)
μ
(
d
)
⌊
n
p
r
i
m
e
[
i
]
∗
d
⌋
⌊
m
p
r
i
m
e
[
i
]
∗
d
⌋
这里
T
=
p
r
i
m
e
[
i
]
∗
d
可以将式子转化为
=
∑
T
=
1
m
a
x
(
n
,
m
)
⌊
n
T
⌋
⌊
m
T
⌋
∑
k
∣
T
,
k
∈
p
r
i
m
e
μ
(
T
k
)
\sum_{x=1}^{n}\sum_{y=1}^m [gcd(x,y)=p]\\ =\sum_{i=1}^{tot}\sum_{x=1}^{n}\sum_{y=1}^m [gcd(x,y)=prime[i]]\\ =\sum_{i=1}^{tot}\sum_{x=1}^{\lfloor\frac{n}{prime[i]}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{prime[i]}\rfloor} [gcd(x,y)=1]\\ =\sum_{i=1}^{tot}\sum_{d=1}^{max(n,m)}\mu(d)\lfloor\frac{n}{prime[i]*d}\rfloor\lfloor\frac{m}{prime[i]*d}\rfloor\\ 这里T=prime[i]*d可以将式子转化为\\ =\sum_{T=1}^{max(n,m)}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{k|T,k\in prime}\mu(\frac{T}{k})
x=1∑ny=1∑m[gcd(x,y)=p]=i=1∑totx=1∑ny=1∑m[gcd(x,y)=prime[i]]=i=1∑totx=1∑⌊prime[i]n⌋y=1∑⌊prime[i]m⌋[gcd(x,y)=1]=i=1∑totd=1∑max(n,m)μ(d)⌊prime[i]∗dn⌋⌊prime[i]∗dm⌋这里T=prime[i]∗d可以将式子转化为=T=1∑max(n,m)⌊Tn⌋⌊Tm⌋k∣T,k∈prime∑μ(kT)
发现后面一个式子
∑
k
∣
T
,
k
∈
p
r
i
m
e
μ
(
T
k
)
\sum_{k|T,k\in prime}\mu(\frac{T}{k})
∑k∣T,k∈primeμ(kT)是可以预处理出来的,这样就减少了复杂度
P1829 [国家集训队]Crash的数字表格 / JZPTAB
简要题意
求 ∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) ∑i=1n∑j=1mlcm(i,j)
推导
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 m i j g c d ( i , j ) = ∑ d = 1 m a x ( n , m ) ∑ i = 1 n ∑ j = 1 m i j d [ g c d ( i , j ) = d ] = ∑ d = 1 m a x ( n , m ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j d [ g c d ( i , j ) = 1 ] = ∑ d = 1 m a x ( n , m ) d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j [ g c d ( i , j ) = 1 ] 设 s u m ( n , m ) = ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = 1 ] 化简这个式子 ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = 1 ] = ∑ d = 1 m a x ( n , m ) μ ( d ) d 2 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j 设 f ( n , m ) = ∑ i = 1 n ∑ j = 1 m i j 化简这个式子有 ∑ i = 1 n ∑ j = 1 m i j = ∑ i = 1 n i ∑ j = 1 m j = ( n + 1 ) n 2 ⋅ ( m + 1 ) m 2 所以 s u m ( n , m ) = ∑ d = 1 m a x ( n , m ) μ ( d ) ⋅ d 2 ⋅ f ( n d , m d ) 原式 = ∑ d = 1 m a x ( n , m ) d ⋅ s u m ( n d , m d ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{gcd(i,j)}\\ =\sum_{d=1}^{max(n,m)}\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{d}[gcd(i,j)=d]\\ =\sum_{d=1}^{max(n,m)}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ijd[gcd(i,j)=1]\\ =\sum_{d=1}^{max(n,m)}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij[gcd(i,j)=1]\\ 设sum(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}ij[gcd(i,j)=1]\\ 化简这个式子\\ \sum_{i=1}^{n}\sum_{j=1}^{m}ij[gcd(i,j)=1]\\ =\sum_{d=1}^{max(n,m)}\mu(d)d^2\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij\\ 设f(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}ij\\ 化简这个式子有\\ \sum_{i=1}^{n}\sum_{j=1}^{m}ij\\ =\sum_{i=1}^{n}i\sum_{j=1}^{m}j\\ =\frac{(n+1)n}{2}\cdot \frac{(m+1)m}{2}\\ 所以sum(n,m)=\sum_{d=1}^{max(n,m)}\mu(d)\cdot d^2\cdot f(\frac{n}{d},\frac{m}{d})\\ 原式=\sum_{d=1}^{max(n,m)}d\cdot sum(\frac{n}{d}, \frac{m}{d}) i=1∑nj=1∑mlcm(i,j)=i=1∑nj=1∑mgcd(i,j)ij=d=1∑max(n,m)i=1∑nj=1∑mdij[gcd(i,j)=d]=d=1∑max(n,m)i=1∑⌊dn⌋j=1∑⌊dm⌋ijd[gcd(i,j)=1]=d=1∑max(n,m)di=1∑⌊dn⌋j=1∑⌊dm⌋ij[gcd(i,j)=1]设sum(n,m)=i=1∑nj=1∑mij[gcd(i,j)=1]化简这个式子i=1∑nj=1∑mij[gcd(i,j)=1]=d=1∑max(n,m)μ(d)d2i=1∑⌊dn⌋j=1∑⌊dm⌋ij设f(n,m)=i=1∑nj=1∑mij化简这个式子有i=1∑nj=1∑mij=i=1∑nij=1∑mj=2(n+1)n⋅2(m+1)m所以sum(n,m)=d=1∑max(n,m)μ(d)⋅d2⋅f(dn,dm)原式=d=1∑max(n,m)d⋅sum(dn,dm)
这里的两个式子都可以用整除分块+前缀和的方式加速
代码
#include <bits/stdc++.h>
const int N = 1e7 + 5, mod = 20101009;
inline int add(int a, int b) { return (a += b) >= mod ? a - mod : a; }
inline int sub(int a, int b) { return (a -= b) < 0 ? a + mod : a; }
inline int mul(int a, int b) { return 1LL * a * b % mod; }
std::vector < int > prime;
int v[N], mu[N], sum[N];
void input(int n) {
mu[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!v[i]) prime.push_back(i), v[i] = i, mu[i] = mod - 1;
for(auto x : prime) {
if(x > n / i) break;
v[i * x] = x;
if(!(i % x)) {
mu[x * i] = 0;
break;
}
mu[i * x] = sub(mod, mu[i]);
}
}
for(int i = 1; i <= n; ++i) sum[i] = add(sum[i - 1], mul(mu[i], mul(i, i)));
}
inline int sumij(int i, int j) {
return mul((1LL * (i + 1) * i / 2) % mod, (1LL * (j + 1) * j / 2) % mod);
}
inline int f(int n, int m) {
int re = 0;
for(int l = 1, r; l <= m; l = r + 1) {
r = std::min(n / (n / l), m / (m / l));
int cnt1 = n / l, cnt2 = m / l;
re = add(re, mul(sumij(cnt1, cnt2), sub(sum[r], sum[l - 1])));
}
return re;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
if(n < m) std::swap(n, m);
input(n);
int ans = 0;
for(int d = 1; d <= n; ++d) {
ans = add(ans, mul(d, f(n / d, m / d)));
}
std::cout << ans << '\n';
return 0;
}
杜教筛
对于任意一个数论函数
g
g
g,必满足:
∑
i
=
1
n
(
f
∗
g
)
(
i
)
=
∑
i
=
1
n
∑
d
∣
i
g
(
d
)
f
(
i
d
)
=
∑
i
=
1
n
g
(
i
)
S
(
⌊
n
i
⌋
)
\sum_{i=1}^{n}(f*g)(i)=\sum_{i=1}^{n}\sum_{d|i}g(d)f(\frac{i}{d})=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)
i=1∑n(f∗g)(i)=i=1∑nd∣i∑g(d)f(di)=i=1∑ng(i)S(⌊in⌋)
重要推论:
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
g
(
i
)
S
(
⌊
n
i
⌋
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
=
∑
i
=
1
n
(
f
∗
g
)
(
i
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\ =\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)
g(1)S(n)=i=1∑ng(i)S(⌊in⌋)−i=2∑ng(i)S(⌊in⌋)=i=1∑n(f∗g)(i)−i=2∑ng(i)S(⌊in⌋)
如果可以构造一个数论函数 g g g使得:
- 可以快速计算 ∑ i = 1 n ( f ∗ g ) ( i ) \sum_{i=1}^{n}(f*g)(i) ∑i=1n(f∗g)(i)
- 可以快速计算
g
g
g的前缀和,这样就能用数论分块求解
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)
∑i=2ng(i)S(⌊in⌋)
则我们可以取 m = 2 3 n m=\frac{2}{3}n m=32n的复杂度求得 g ( 1 ) S ( n ) g(1)S(n) g(1)S(n)
P3768 简单的数学题
∑ i = 1 n ∑ j = 1 n i j g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 n i j ∑ k ∣ i , k ∣ j φ ( k ) = ∑ k = 1 n φ ( k ) ∑ k ∣ i ∑ k ∣ i i j = ∑ k = 1 n φ ( k ) × k 2 × ( ∑ i = 1 ⌊ n k ⌋ i ) 2 = ∑ k = 1 n φ ( k ) × k 2 × ∑ i = 1 ⌊ n k ⌋ i 3 \sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{n}ij\sum_{k|i,k|j}\varphi(k)\\ =\sum_{k=1}^{n}\varphi(k)\sum_{k|i}\sum_{k|i}ij\\ =\sum_{k=1}^{n}\varphi(k)\times k^2 \times (\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i)^2\\ =\sum_{k=1}^{n}\varphi(k)\times k^2 \times \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i^3 i=1∑nj=1∑nijgcd(i,j)=i=1∑nj=1∑nijk∣i,k∣j∑φ(k)=k=1∑nφ(k)k∣i∑k∣i∑ij=k=1∑nφ(k)×k2×(i=1∑⌊kn⌋i)2=k=1∑nφ(k)×k2×i=1∑⌊kn⌋i3
对 φ ( k ) k 2 \varphi(k)k^2 φ(k)k2做杜教筛
把 k k k看成 I d Id Id函数有, f = I d 2 φ f=Id^2\varphi f=Id2φ,卷一个 g = I d 2 g=Id^2 g=Id2可以得到 ( f ∗ g ) ( n ) = n 3 (f*g)(n)=n^3 (f∗g)(n)=n3
这里有一个结论就是 I d k Id^k Idk卷一个 I d k Id^k Idk可以看成是 ( I d k ∗ I d k ) ( n ) = n k ( n − φ ( n ) ) (Id^k*Id^k)(n)=n^k(n-\varphi(n)) (Idk∗Idk)(n)=nk(n−φ(n))
Powerful Number筛
Powerful Number(以下叫做PN)的定义:设 n = ∏ i = 1 m p i e i n=\prod_{i=1}^{m}p_i^{e_i} n=∏i=1mpiei只有所有的 e i > 1 e_i\gt 1 ei>1才能是PN
可以证明PN的数量级是 Θ ( n ) \Theta(\sqrt n) Θ(n)的,也就是可以暴力搜索所有小于 n \sqrt n n的质数处理出PN
Powerful Number筛其实是杜教筛的升级版本,计算的也是 F ( n ) = ∑ i = 1 n f ( i ) F(n)=\sum_{i=1}^n f(i) F(n)=∑i=1nf(i)( f ( i ) f(i) f(i)是积性函数),但是依然不适用于所有场景。
PN筛的步骤:
- 找到一个积性函数 g ( n ) g(n) g(n)在 n n n为质数的时候 g ( p ) = f ( p ) g(p)=f(p) g(p)=f(p),并且 G ( n ) = ∑ i = 1 n g ( i ) G(n)=\sum_{i=1}^n g(i) G(n)=∑i=1ng(i)
- 找到一个快速计算 G G G也就是 g g g的前缀和的方法
- 令 f = g ∗ h f = g*h f=g∗h,此时有 h h h为积性函数且 h ( 1 ) = 1 h(1) = 1 h(1)=1
- 最后 F ( n ) = ∑ d = 1 , d i s P N n h ( d ) G ( ⌊ n d ⌋ ) F(n)=\sum_{d=1,d\ is\ PN}^{n}h(d)G(\lfloor\frac{n}{d}\rfloor) F(n)=∑d=1,d is PNnh(d)G(⌊dn⌋)
下面是对于这条公式的证明(可跳过):
首先对于 h h h函数有一个特殊性质:
f
(
p
)
=
g
(
p
)
h
(
1
)
+
g
(
1
)
h
(
p
)
=
g
(
p
)
h
(
p
)
=
0
f(p)=g(p)h(1)+g(1)h(p)=g(p)\\ h(p)=0
f(p)=g(p)h(1)+g(1)h(p)=g(p)h(p)=0
因为
h
h
h是一个积性函数,我们知道
h
(
n
o
t
P
N
)
=
0
h(not\ PN)=0
h(not PN)=0
于是
F
(
n
)
=
∑
i
=
1
n
∑
d
∣
i
h
(
d
)
∗
g
(
⌊
i
d
⌋
)
=
∑
d
=
1
n
h
(
d
)
∑
i
=
1
⌊
n
d
⌋
g
(
i
)
=
∑
d
=
1
n
h
(
d
)
G
(
⌊
n
d
⌋
)
=
∑
d
=
1
,
d
i
s
P
N
n
h
(
d
)
G
(
⌊
n
d
⌋
)
F(n)=\sum_{i=1}^n \sum_{d|i}h(d)*g(\lfloor\frac{i}{d}\rfloor)\\ =\sum_{d=1}^n h(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}g(i)\\ =\sum_{d=1}^n h(d)G(\lfloor\frac{n}{d}\rfloor)\\ =\sum_{d=1,d\ is\ PN}^{n}h(d)G(\lfloor\frac{n}{d}\rfloor)
F(n)=i=1∑nd∣i∑h(d)∗g(⌊di⌋)=d=1∑nh(d)i=1∑⌊dn⌋g(i)=d=1∑nh(d)G(⌊dn⌋)=d=1,d is PN∑nh(d)G(⌊dn⌋)
得证
P5325【模板】Min_25 筛
给定
f
(
p
k
)
=
p
k
(
p
k
−
1
)
f(p^k)=p^k(p^k-1)
f(pk)=pk(pk−1),求
∑
i
=
1
n
f
(
i
)
\sum_{i=1}^n f(i)
∑i=1nf(i)
定义
g
(
n
)
=
I
d
(
n
)
φ
(
n
)
此时
G
(
n
)
可以通过杜教筛快速得出
G
(
n
)
=
∑
i
=
1
n
i
2
−
∑
d
=
2
n
d
∗
G
(
⌊
n
d
⌋
)
那么我们知道
h
(
p
k
)
可以枚举计算(法
1
)
另外也有
h
(
p
k
)
直接推出的公式
f
(
p
k
)
=
∑
i
=
0
k
g
(
p
k
−
i
)
h
(
p
i
)
p
k
(
p
k
−
1
)
=
∑
i
=
0
k
p
k
−
i
φ
(
p
i
)
h
(
p
i
)
p
k
(
p
k
−
1
)
=
∑
i
=
0
k
p
2
k
−
2
i
−
1
(
p
−
1
)
h
(
p
i
)
h
(
p
k
)
=
p
k
(
p
k
−
1
)
−
∑
i
=
0
k
−
1
p
2
k
−
2
i
−
1
h
(
p
i
)
h
(
p
k
)
−
p
2
h
(
p
k
−
1
)
=
p
k
(
p
k
−
1
)
−
p
k
+
1
(
p
k
−
1
−
1
)
−
p
(
p
−
1
)
h
(
p
k
−
1
)
h
(
p
k
)
−
p
h
(
p
k
−
1
)
=
p
k
+
1
−
p
k
h
(
p
k
)
p
k
−
h
(
p
k
−
1
)
p
k
−
1
=
p
−
1
有
h
(
p
)
=
0
推出
h
(
p
k
)
=
(
k
−
1
)
(
p
−
1
)
p
k
(法二)
时间复杂度相似但是法二比较好写
定义g(n)=Id(n)\varphi(n)\\ 此时G(n)可以通过杜教筛快速得出\\ G(n)=\sum_{i=1}^n i^2-\sum_{d=2}^n d*G(\lfloor\frac{n}{d}\rfloor)\\ 那么我们知道h(p^k)可以枚举计算(法1)\\ 另外也有h(p^k)直接推出的公式\\ f(p^k)=\sum_{i=0}^k g(p^{k-i})h(p^i)\\ p^k(p^k-1)=\sum_{i=0}^k p^{k-i}\varphi(p^i)h(p^i)\\ p^k(p^k-1)=\sum_{i=0}^k p^{2k-2i-1}(p-1)h(p^i)\\ h(p^k)=p^k(p^k-1)-\sum_{i=0}^{k-1} p^{2k-2i-1}h(p^i)\\ h(p^k)-p^2h(p^{k-1})=p^k(p^k-1)-p^{k+1}(p^{k-1}-1)-p(p-1)h(p^{k-1})\\ h(p^k)-ph(p^{k-1})=p^{k+1}-p^k\\ \frac{h(p^k)}{p^k}-\frac{h(p^{k-1})}{p^{k-1}}=p-1\\ 有h(p)=0推出\\ h(p^k)=(k-1)(p-1)p^k(法二)\\ 时间复杂度相似但是法二比较好写\\
定义g(n)=Id(n)φ(n)此时G(n)可以通过杜教筛快速得出G(n)=i=1∑ni2−d=2∑nd∗G(⌊dn⌋)那么我们知道h(pk)可以枚举计算(法1)另外也有h(pk)直接推出的公式f(pk)=i=0∑kg(pk−i)h(pi)pk(pk−1)=i=0∑kpk−iφ(pi)h(pi)pk(pk−1)=i=0∑kp2k−2i−1(p−1)h(pi)h(pk)=pk(pk−1)−i=0∑k−1p2k−2i−1h(pi)h(pk)−p2h(pk−1)=pk(pk−1)−pk+1(pk−1−1)−p(p−1)h(pk−1)h(pk)−ph(pk−1)=pk+1−pkpkh(pk)−pk−1h(pk−1)=p−1有h(p)=0推出h(pk)=(k−1)(p−1)pk(法二)时间复杂度相似但是法二比较好写
void solve() {
i64 n;
std::cin >> n;
int N1 = 10000000, N2 = sqrt(n);
std::vector < int > prime, phi(N1 + 1), v(N1 + 1);
std::vector < MInt > g(N1 + 1), s(N1 + 1);
phi[1] = 1;
for(int i = 2; i <= N1; ++i) {
if(!v[i]) prime.emplace_back(i), v[i] = i, phi[i] = i - 1;
for(auto x : prime) {
if(x > N1 / i || x > v[i]) break;
v[i * x] = x;
phi[i * x] = phi[i] * (i % x == 0 ? x : x - 1);
}
}
for(int i = 1; i <= N1; ++i) g[i] = 1LL * i * phi[i], s[i] = s[i - 1] + g[i];
MInt inv6 = MInt(6).inverse(), inv2 = 500000004;
std::unordered_map < i64 , MInt > mp;
auto G = [&](auto self, i64 n) -> MInt {
if(n <= N1) return s[n];
if(mp.count(n)) return mp[n];
MInt re = MInt(n) * MInt(n + 1) * MInt(2 * n + 1) * inv6;
for(i64 l = 2, r; l <= n; l = r + 1) {
r = std::min(n, n / (n / l));
re -= (MInt(r) * MInt(r + 1) * inv2 - MInt(l - 1) * MInt(l) * inv2) * self(self, n / l);
}
return mp[n] = re;
} ;
// std::cout << g[2] << ' ' << g[3] << ' ' << g[6] << ' ' << g[9] << '\n';
MInt ans = 0;
auto dfs = [&](auto self, int id, i64 now, MInt re) -> void {
i64 cnt = 1LL * prime[id] * prime[id];
if(now > n / cnt) {
// std::cout << now << ' ' << prime[id] << ' ' << n << '\n';
ans += re * G(G, n / now);
return ;
}
self(self, id + 1, now, re);
MInt st = cnt * g[prime[id]];
i64 las = n / now;
while(cnt <= las) {
MInt to = (MInt(cnt) * MInt(cnt - 1) - st);
self(self, id + 1, now * cnt, re * to);
if(cnt > las / prime[id]) break;
st *= prime[id] * prime[id];
st += to * g[prime[id]];
cnt *= prime[id];
}
} ;
dfs(dfs, 0, 1, 1);
std::cout << ans << '\n';
}
void solve() {
i64 n;
std::cin >> n;
int N1 = 10000000, N2 = sqrt(n);
std::vector < int > prime, phi(N1 + 1), v(N1 + 1);
std::vector < MInt > g(N1 + 1), s(N1 + 1);
phi[1] = 1;
for(int i = 2; i <= N1; ++i) {
if(!v[i]) prime.emplace_back(i), v[i] = i, phi[i] = i - 1;
for(auto x : prime) {
if(x > N1 / i || x > v[i]) break;
v[i * x] = x;
phi[i * x] = phi[i] * (i % x == 0 ? x : x - 1);
}
}
for(int i = 1; i <= N1; ++i) g[i] = 1LL * i * phi[i], s[i] = s[i - 1] + g[i];
MInt inv6 = MInt(6).inverse(), inv2 = 500000004;
std::unordered_map < i64 , MInt > mp;
auto G = [&](auto self, i64 n) -> MInt {
if(n <= N1) return s[n];
if(mp.count(n)) return mp[n];
MInt re = MInt(n) * MInt(n + 1) * MInt(2 * n + 1) * inv6;
for(i64 l = 2, r; l <= n; l = r + 1) {
r = std::min(n, n / (n / l));
re -= (MInt(r) * MInt(r + 1) * inv2 - MInt(l - 1) * MInt(l) * inv2) * self(self, n / l);
}
return mp[n] = re;
} ;
// std::cout << g[2] << ' ' << g[3] << ' ' << g[6] << ' ' << g[9] << '\n';
MInt ans = 0;
auto dfs = [&](auto self, int id, i64 now, MInt re) -> void {
i64 cnt = 1LL * prime[id] * prime[id];
if(now > n / cnt) {
// std::cout << now << ' ' << prime[id] << ' ' << n << '\n';
ans += re * G(G, n / now);
return ;
}
self(self, id + 1, now, re);
MInt i = prime[id] - 1;
i64 las = n / now;
while(cnt <= las) {
self(self, id + 1, now * cnt, re * i * MInt(cnt));
if(cnt > las / prime[id]) break;
i += MInt(prime[id] - 1);
cnt *= prime[id];
}
} ;
dfs(dfs, 0, 1, 1);
std::cout << ans << '\n';
}
Min_25筛
使用要求
在 Θ ( n 3 4 l o g n ) \Theta(\frac{n^{\frac{3}{4}}}{log\ n}) Θ(log nn43)的时间复杂度下解决积性函数的前缀和问题。
要求 f ( p ) f(p) f(p)是一个关于 p p p的项数较少的多项式或可以快速求值, f ( p c ) f(p^c) f(pc)可以快速求值。
定义说明
p p p没有特殊说明时代表全体质数
i s p r i m e ( n ) isprime(n) isprime(n)表示 n n n为质数时为 1 1 1
p k p_k pk表示全体质数中第 k k k小的质数,特别的 p 0 = 1 p_0=1 p0=1
l p f ( n ) : = [ 1 < n ] m i n { p : p ∣ n } + [ 1 = n ] lpf(n):=[1<n]min\{p:p|n\}+[1=n] lpf(n):=[1<n]min{p:p∣n}+[1=n]表示 n n n的最小质因数。特别的, l p f ( 1 ) = 1 lpf(1)=1 lpf(1)=1
F p r i m e ( n ) : = ∑ 2 ≤ p ≤ n f ( p ) F_{prime}(n):=\sum_{2\le p \le n}f(p) Fprime(n):=∑2≤p≤nf(p)
F k ( n ) : = ∑ i = 2 n [ p k ≤ l p f ( i ) ] f ( i ) F_k(n):=\sum_{i=2}^n [p_k\le lpf(i)]f(i) Fk(n):=∑i=2n[pk≤lpf(i)]f(i)
使用方法
观察 F k ( n ) F_k(n) Fk(n)的定义,我们要求 ∑ i = 1 n f ( i ) = F 1 ( n ) + f ( 1 ) = F 1 ( n ) + 1 \sum_{i=1}^n f(i)=F_1(n)+f(1)=F_1(n)+1 ∑i=1nf(i)=F1(n)+f(1)=F1(n)+1
考虑如何求出
F
k
(
n
)
F_k(n)
Fk(n)
F
k
(
n
)
=
∑
i
=
2
n
[
p
k
≤
l
p
f
(
i
)
]
f
(
i
)
=
∑
k
≤
i
,
p
i
2
≤
n
∑
1
≤
c
,
p
i
c
≤
n
f
(
p
c
)
(
[
c
>
1
]
+
F
i
+
1
(
⌊
n
p
i
c
⌋
)
)
+
∑
k
≤
i
,
p
i
≤
n
f
(
p
i
)
=
∑
k
≤
i
,
p
i
2
≤
n
(
∑
1
≤
c
,
p
i
c
≤
n
f
(
p
c
)
(
[
c
>
1
]
+
F
i
+
1
(
⌊
n
p
i
c
⌋
)
)
+
F
p
r
i
m
e
(
n
)
−
F
p
r
i
m
e
(
p
k
−
1
)
)
=
∑
k
≤
i
,
p
i
2
≤
n
(
∑
1
≤
c
,
p
i
c
+
1
≤
n
(
f
(
p
c
)
F
i
+
1
(
⌊
n
p
i
c
⌋
)
+
f
(
p
i
c
+
1
)
)
+
F
p
r
i
m
e
(
n
)
−
F
p
r
i
m
e
(
p
k
−
1
)
)
F_k(n)=\sum_{i=2}^n [p_k\le lpf(i)]f(i)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ =\sum_{k\le i,p_i^2\le n}\sum_{1\le c,p_i^c\le n}f(p^c)([c>1]+F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor))+\sum_{k\le i, p_i\le n}f(p_i)\\ =\sum_{k\le i,p_i^2\le n}(\sum_{1\le c,p_i^c\le n}f(p^c)([c>1]+F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor))+F_{prime}(n)-F_{prime}(p_{k-1}))\\ =\sum_{k\le i,p_i^2\le n}(\sum_{1\le c,p_i^{c+1}\le n}(f(p^c)F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor)+f(p_i^{c+1}))+F_{prime}(n)-F_{prime}(p_{k-1}))\\
Fk(n)=i=2∑n[pk≤lpf(i)]f(i) =k≤i,pi2≤n∑1≤c,pic≤n∑f(pc)([c>1]+Fi+1(⌊picn⌋))+k≤i,pi≤n∑f(pi)=k≤i,pi2≤n∑(1≤c,pic≤n∑f(pc)([c>1]+Fi+1(⌊picn⌋))+Fprime(n)−Fprime(pk−1))=k≤i,pi2≤n∑(1≤c,pic+1≤n∑(f(pc)Fi+1(⌊picn⌋)+f(pic+1))+Fprime(n)−Fprime(pk−1))
最后一步推导的说明
对于满足 p i c ≤ n < p i c + 1 p_i^c\le n< p_i^{c+1} pic≤n<pic+1的 c c c,有 ⌊ n p i c ⌋ < p i < p i + 1 \lfloor\frac{n}{p_i^c}\rfloor <p_i<p_{i+1} ⌊picn⌋<pi<pi+1。
故 F i + 1 ( ⌊ n p i c ⌋ ) = 0 F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor)=0 Fi+1(⌊picn⌋)=0
有 F k ( n ) = 0 ( p k > n ) F_k(n)=0(p_k>n) Fk(n)=0(pk>n)。
假设现在已经求出了所有的 F p r i m e ( n ) F_{prime}(n) Fprime(n),那么有两种方式可以求出所有的 F k ( n ) F_k(n) Fk(n):
- 直接按照递推式计算
- 从大到小枚举 p p p转移,仅当 p 2 < n p^2<n p2<n时转移增加值不为零,故按照递推式后缀和优化即可。
计算 F p r i m e ( n ) F_{prime}(n) Fprime(n)
一般情况下 f ( p ) f(p) f(p)是一个关于 p p p的低次多项式,可以表示成 f ( p ) = ∑ a i p c i f(p)=\sum a_ip^{c_i} f(p)=∑aipci
那么对于每个 p c i p^{c_i} pci,其对 F p r i m e ( n ) F_{prime}(n) Fprime(n)的贡献可以表示为 a i ∑ 2 ≤ p ≤ n p c i a_i\sum_{2\le p\le n}p^{c_i} ai∑2≤p≤npci
分开考虑每个 p c i p^{c_i} pci的贡献,问题就转变为了:给定 n , s , g ( p ) = p s n,s,g(p)=p^s n,s,g(p)=ps,对所有的 m = ⌊ n i ⌋ m=\lfloor\frac{n}{i}\rfloor m=⌊in⌋,求 ∑ p ≤ m g ( p ) \sum_{p\le m}g(p) ∑p≤mg(p)。
设:
G
x
(
n
)
=
∑
2
≤
i
≤
n
[
i
s
p
r
i
m
e
(
i
)
o
r
p
x
<
l
p
f
(
i
)
]
g
(
i
)
G_x(n)=\sum_{2\le i \le n}[isprime(i)\ or\ p_x<lpf(i)]g(i)\\
Gx(n)=2≤i≤n∑[isprime(i) or px<lpf(i)]g(i)
即埃氏筛第
k
k
k轮晒完后剩下的数的
g
g
g值之和。
对于一个合数 x x x,必然有 l p f ( x ) ≤ x lpf(x)\le\sqrt{x} lpf(x)≤x,则 F p r i m e = G n F_{prime}=G_{\sqrt{n}} Fprime=Gn故只需筛到 G n G_{\sqrt{n}} Gn即可
考虑 G G G的边界值, G 0 ( n ) = ∑ i = 2 n g ( i ) G_0(n)=\sum_{i=2}^n g(i) G0(n)=∑i=2ng(i)
对于转移,考虑埃氏筛的过程,分开讨论每部分的贡献,有:
- 对于 n < p k 2 n<p_k^2 n<pk2的部分, G G G值不变,即 G x ( n ) = G x − 1 ( n ) G_x(n)=G_{x-1}(n) Gx(n)=Gx−1(n)
- 对于 p k 2 ≤ n p_k^2\le n pk2≤n部分,被筛掉的数必有质因子 p k p_k pk即 − g ( p k ) G k − 1 ( ⌊ n p k ⌋ ) -g(p_k)G_{k-1}(\lfloor\frac{n}{p_k}\rfloor) −g(pk)Gk−1(⌊pkn⌋)
- 对于第二个部分,会有一些 l p f ( i ) < p k lpf(i)<p_k lpf(i)<pk的 i i i被减去,加回来的贡献是 g ( p k ) G k − 1 ( p k − 1 ) g(p_k)G_{k-1}(p_{k-1}) g(pk)Gk−1(pk−1)
则可以得到 G k ( n ) = G k − 1 ( n ) − [ p k 2 ≤ n ] g ( p k ) ( G k − 1 ( ⌊ n p k ⌋ ) − G k − 1 ( p k − 1 ) ) G_k(n)=G_{k-1}(n)-[p_k^2\le n]g(p_k)(G_{k-1}(\lfloor\frac{n}{p_k}\rfloor)-G_{k-1}(p_{k-1})) Gk(n)=Gk−1(n)−[pk2≤n]g(pk)(Gk−1(⌊pkn⌋)−Gk−1(pk−1))
总结
对于 F k ( n ) F_k(n) Fk(n)的计算,利用第一种方式写一个函数,这个实现难度较低,已经适用于大部分题目。
对于 F p r i m e 的计算 F_{prime}的计算 Fprime的计算,直接按递推式实现即可。
对于 p k 2 ≤ n p_k^2\le n pk2≤n可以用线性筛预处理出 s k : = F p r i m e ( p k ) s_k:=F_{prime}(p_k) sk:=Fprime(pk)来代替 F k F_k Fk递推式中的 F p r i m e ( p k − 1 ) F_{prime}(p_{k-1}) Fprime(pk−1)
相应的 G k − 1 ( p k − 1 ) = ∑ i = 1 k − 1 g ( p i ) G_{k-1}(p_{k-1})=\sum_{i=1}^{k-1}g(p_i) Gk−1(pk−1)=∑i=1k−1g(pi)也可以预处理。
用埃氏筛求 f f f的前缀和时,应当明确以下几点:
- 如何快速(一般是线性复杂度)筛出前 n \sqrt{n} n个 f f f值
- f ( p ) f(p) f(p)的多项式表示
- 如何快速求出 f ( p c ) f(p^c) f(pc)
明确上述几点之后按顺序实现以下几部分即可:
- 筛出 [ 1 , n ] [1, \sqrt{n}] [1,n]内的质数与前 n \sqrt{n} n个 f f f值;
- 对 f ( p ) f(p) f(p)多项式表示中的每一项筛出对应的 G G G,合并得到 F p r i m e F_{prime} Fprime的所有 O ( n ) O(\sqrt{n}) O(n)有用点值
- 按照 F k F_{k} Fk的递推式实现递归,求出 F 1 ( n ) F_{1}(n) F1(n)
P5325【模板】Min_25 筛
const int N = 2e5;
i64 n, lim;
void solve() {
std::cin >> n;
lim = sqrt(n);
std::vector < int > prime, v(N + 10);
std::vector < MInt > sum1(N + 10), sum2(N + 10);
for(int i = 2; i <= N; ++i) {
if(!v[i]) {
prime.emplace_back(i);
v[i] = i;
}
for(auto x : prime) {
if(x > N / i || x > v[i]) break;
v[i * x] = x;
}
}
for(int i = 0; i < prime.size(); ++i) {
sum1[i + 1] = sum1[i] + prime[i];
sum2[i + 1] = sum2[i] + MInt(1LL * prime[i] * prime[i]);
}
MInt inv2 = MInt(2).inverse(), inv6 = MInt(6).inverse();
auto f1 = [&](i64 n) -> MInt {
return MInt(n) * MInt(n + 1) * inv2;
} ;
auto f2 = [&](i64 n) -> MInt {
return MInt(n) * MInt(n + 1) * MInt(2 * n + 1) * inv6;
} ;
std::vector < i64 > idpre(N + 10), idsuf(N + 10), w;
std::vector < std::vector < MInt > > G(2, std::vector < MInt > (N + 10));
for(i64 l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
w.emplace_back(n / l);
G[0][w.size()] = f1(n / l) - 1, G[1][w.size()] = f2(n / l) - 1;
if(n / l <= lim) idpre[n / l] = w.size();
else idsuf[r] = w.size();
}
// std::cerr << '\n';
auto id = [&](i64 x) -> i64 {
if(x <= lim) return idpre[x];
else return idsuf[n / x];
} ;
for(int i = 0; i < prime.size(); ++i) {
int x = prime[i];
for(int j = 1; j <= w.size() && 1LL * x * x <= w[j - 1]; ++j) {
G[0][j] -= x * (G[0][id(w[j - 1] / x)] - sum1[i]);
G[1][j] -= x * x * (G[1][id(w[j - 1] / x)] - sum2[i]);
}
}
// std::cerr << '\n';
// std::cerr << "123" << '\n';
auto f = [&](MInt pc) -> MInt {
return pc * (pc - 1);
} ;
auto F = [&](auto self, int k, i64 n) -> MInt {
if(prime[k] > n) return 0;
MInt ans = ((G[1][id(n)] - G[0][id(n)]) - (sum2[k] - sum1[k]));
for(int i = k; i < prime.size() && prime[i] * prime[i] <= n; ++i) {
for(i64 c = 1, sp = prime[i]; sp <= n / prime[i]; ++c, sp *= prime[i]) {
ans += f(MInt(sp)) * self(self, i + 1, n / sp) + f(MInt(sp * prime[i]));
}
}
return ans;
} ;
std::cout << F(F, 0, n) + 1 << '\n';
}
2024GDCPC 另一个计数问题
题解
注意到,对于所有 x ≤ ⌊ n + 1 2 ⌋ x \le \lfloor \frac{n + 1}{2} \rfloor x≤⌊2n+1⌋ 的结点 x x x, x x x 与 2 x 2x 2x 间有一条边,而 2 x 2x 2x 与 2 2 2 之间有一条边,因此所有 2 ∼ ⌊ n + 1 2 ⌋ 2 \sim \lfloor \frac{n + 1}{2} \rfloor 2∼⌊2n+1⌋ 范围内的结点连通。而对于 x > ⌊ n + 1 2 ⌋ x > \lfloor \frac{n + 1}{2} \rfloor x>⌊2n+1⌋ 的结点 x x x, x x x 不与 2 ∼ ⌊ n + 1 2 ⌋ 2 \sim \lfloor \frac{n + 1}{2} \rfloor 2∼⌊2n+1⌋ 中的结点连通当且仅当 x x x 为素数。因此整个图仅包含若干个单独的素数结点与一个大的连通块。
考虑计算不连通的点对之间的贡献。不难发现,只需要求出所有 > ⌊ n + 1 2 ⌋ > \lfloor \frac{n + 1}{2} \rfloor >⌊2n+1⌋ 的素数的和与平方和。使用 Min_25 筛或分块打表均可。
2024杭电多校第2场 1004 a*b problem
题意
求出 b = x 1 t 1 x 2 t 2 x 3 t 3 . . . x k t k , 1 ≤ b ≤ n b=x_1^{t_1}x_2^{t_2}x_3^{t_3}...x_k^{t_k},1\le b\le n b=x1t1x2t2x3t3...xktk,1≤b≤n在 g c d ( x 1 , x 2 , . . . , x k ) = 1 gcd(x_1,x_2,...,x_k)=1 gcd(x1,x2,...,xk)=1时,
( x 1 , x 2 , . . . , x k ) (x_1,x_2,...,x_k) (x1,x2,...,xk)有序对的数量。
题解
设 f ( n ) f(n) f(n)表示 n = x 1 t 1 x 2 t 2 x 3 t 3 . . . x k t k n=x_1^{t_1}x_2^{t_2}x_3^{t_3}...x_k^{t_k} n=x1t1x2t2x3t3...xktk时 ( x 1 , x 2 , . . . , x k ) (x_1,x_2,...,x_k) (x1,x2,...,xk)有序对的数量。
即答案为 ∑ i = 1 n f ( i ) \sum_{i=1}^n f(i) ∑i=1nf(i)。
如果在这里可以联想到Min_25筛的话,我们可以发现 f ( p c ) f(p^c) f(pc)其实是与 p p p无关的,即 p p p的 0 0 0次多项式。
此时我们知道 f ( p ) f(p) f(p)就是 t 1 , t 2 , . . . , t k t_1,t_2,...,t_k t1,t2,...,tk中 1 1 1的数量,那么 F p r i m e ( n ) F_{prime}(n) Fprime(n)就是 1 1 1的数量与比 n n n小质数个数的乘积
而 f ( p c ) f(p^c) f(pc)我们知道每次放进 x i t i x_i^{t_i} xiti中,就是放一个 t i t_i ti的倍数在其中。其实就是关于 c c c的一个完全背包,但是这个完全背包有 g c d ( x 1 , x 2 , . . . , x k ) = 1 gcd(x_1,x_2,...,x_k)=1 gcd(x1,x2,...,xk)=1的限制,这个限制其实就是需要保证每个质数放的时候一定会至少有一个 0 0 0的质量,魔改一下完全背包,加一个是否有放 0 0 0就行。
剩下就变成板子了。
const int N = 2e5;
i64 n, lim;
int m;
MInt f[100001][34][2];
void solve() {
std::cin >> n >> m;
std::vector < int > t(m), p(34);
lim = sqrt(n);
for(auto &x : t) std::cin >> x, p[x]++;
if(n == 1) {
std::cout << "1\n";
return ;
}
std::vector < int > prime, v(N + 10);
for(int i = 2; i <= N; ++i) {
if(!v[i]) {
prime.emplace_back(i);
v[i] = i;
}
for(auto x : prime) {
if(x > N / i || x > v[i]) break;
v[i * x] = x;
}
}
MInt inv2 = MInt(2).inverse(), inv6 = MInt(6).inverse();
std::vector < i64 > idpre(N + 10), idsuf(N + 10), w;
std::vector < MInt > G(N + 10);
for(i64 l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
w.emplace_back(n / l);
G[w.size()] = MInt(n / l) - 1;
if(n / l <= lim) idpre[n / l] = w.size();
else idsuf[r] = w.size();
}
auto id = [&](i64 x) -> i64 {
if(x <= lim) return idpre[x];
else return idsuf[n / x];
} ;
for(int i = 0; i < prime.size(); ++i) {
int x = prime[i];
for(int j = 1; j <= w.size() && 1LL * x * x <= w[j - 1]; ++j) {
G[j] -= G[id(w[j - 1] / x)] - i;
}
}
std::vector < MInt > Fprime(w.size() + 1);
for(int i = 1; i <= w.size(); ++i) {
Fprime[i] = G[i] * p[1];
}
for(int i = 1; i <= m; ++i) {
for(int j = 0; j <= 33; ++j) {
f[i][j][0] = f[i][j][1] = 0;
}
}
f[0][0][0] = 1;
for(int i = 1; i <= m; ++i) {
for(int j = 0; j <= 33; j += t[i - 1]) {
if(j == 0) {
for(int k = 0; k <= 33; ++k) {
f[i][k][1] += f[i - 1][k][0] + f[i - 1][k][1];
}
} else {
for(int k = j; k <= 33; ++k) {
f[i][k][0] += f[i - 1][k - j][0];
f[i][k][1] += f[i - 1][k - j][1];
}
}
}
}
auto dp = [&](int c) -> MInt {
if(c > 33) return 0;
return f[m][c][1];
} ;
auto F = [&](auto self, int k, i64 n) -> MInt {
if(prime[k] > n) return 0;
MInt ans = Fprime[id(n)] - k * p[1];
for(int i = k; i < prime.size() && prime[i] * prime[i] <= n; ++i) {
for(i64 c = 1, sp = prime[i]; sp <= n / prime[i]; ++c, sp *= prime[i]) {
ans += dp(c) * self(self, i + 1, n / sp) + dp(c + 1);
}
}
return ans;
} ;
std::cout << F(F, 0, n) + 1 << '\n';
}
628

被折叠的 条评论
为什么被折叠?



