前置知识
狄利克雷卷积
若
f
(
n
)
=
∑
i
∣
n
g
(
i
)
h
(
n
i
)
f(n) = \sum\limits_{i|n}g(i)h(\dfrac{n}{i})
f(n)=i∣n∑g(i)h(in)
则记
f
=
g
∗
h
f = g*h
f=g∗h
杜教筛
假如要求某积性函数
f
(
n
)
f(n)
f(n) 的前缀和
(
n
<
1
0
12
)
(n<10^{12})
(n<1012)。
假设另一个积性函数为
g
(
n
)
g(n)
g(n),
h
=
f
∗
g
h = f*g
h=f∗g,记
s
(
n
)
=
∑
i
=
1
n
f
(
i
)
s(n) = \sum\limits_{i=1}^{n}f(i)
s(n)=i=1∑nf(i)
则有
∑
i
=
1
n
h
(
n
)
=
∑
i
=
1
n
∑
j
∣
i
g
(
j
)
f
(
i
j
)
=
∑
j
=
1
n
g
(
j
)
∑
i
=
1
⌊
n
j
⌋
f
(
i
)
=
∑
j
=
1
n
g
(
j
)
s
(
⌊
n
j
⌋
)
\sum\limits_{i=1}^{n}h(n) = \sum\limits_{i=1}^{n}\sum\limits_{j|i}g(j)f(\dfrac{i}{j})\\=\sum\limits_{j=1}^{n}g(j)\sum\limits_{i=1}^{{\tiny\left\lfloor\dfrac{n}{j}\right\rfloor}}f(i)=\sum\limits_{j=1}^{n}g(j)s(\left\lfloor\dfrac{n}{j}\right\rfloor)
i=1∑nh(n)=i=1∑nj∣i∑g(j)f(ji)=j=1∑ng(j)i=1∑⌊jn⌋f(i)=j=1∑ng(j)s(⌊jn⌋)
然后把
j
=
1
j = 1
j=1 单独拎出来,有
∑
i
=
1
n
h
(
n
)
=
g
(
1
)
s
(
n
)
+
∑
j
=
2
n
g
(
j
)
s
(
⌊
n
j
⌋
)
\sum\limits_{i=1}^{n}h(n)=g(1)s(n) + \sum\limits_{j=2}^{n}g(j)s(\left\lfloor\dfrac{n}{j}\right\rfloor)
i=1∑nh(n)=g(1)s(n)+j=2∑ng(j)s(⌊jn⌋)
那么
s
(
n
)
=
∑
i
=
1
n
h
(
n
)
−
∑
j
=
2
n
g
(
j
)
s
(
⌊
n
j
⌋
)
g
(
1
)
s(n) = \dfrac{\sum\limits_{i=1}^{n}h(n)-\sum\limits_{j=2}^{n}g(j)s(\left\lfloor\dfrac{n}{j}\right\rfloor)}{g(1)}
s(n)=g(1)i=1∑nh(n)−j=2∑ng(j)s(⌊jn⌋)
如果
h
(
n
)
h(n)
h(n) 可以快速求出来,我们就能很快求出
s
(
n
)
s(n)
s(n)
下面举一些例子
求
∑
i
=
1
n
φ
(
n
)
(
n
<
1
0
11
)
\sum\limits_{i = 1}^{n}\varphi(n)~(n<10^{11})
i=1∑nφ(n) (n<1011)
注意到
n
=
∑
i
∣
n
φ
(
i
)
n = \sum\limits_{i|n}\varphi(i)
n=i∣n∑φ(i),也就是
I
d
=
φ
∗
1
Id = \varphi*1
Id=φ∗1
那么我们让
h
(
n
)
=
n
h(n) = n
h(n)=n,
g
(
n
)
=
1
g(n) = 1
g(n)=1
代入上式中,那就有
s
(
n
)
=
n
∗
(
n
+
1
)
2
−
∑
j
=
2
n
s
(
⌊
n
j
⌋
)
s(n)=\dfrac{n*(n+1)}{2}-\sum\limits_{j=2}^{n}s(\left\lfloor\dfrac{n}{j}\right\rfloor)
s(n)=2n∗(n+1)−j=2∑ns(⌊jn⌋)
然后
n
\sqrt{n}
n 枚举关键点
j
j
j,递归求
s
(
⌊
n
j
⌋
)
s(\left\lfloor\dfrac{n}{j}\right\rfloor)
s(⌊jn⌋)
复杂度大概是
O
(
n
3
4
)
O(n^{\tiny\dfrac{3}{4}})
O(n43)
为了加速,我们可以先线性预处理
1
e
7
1e7
1e7 的前缀和
这样递归只用递归大于
1
e
7
1e7
1e7 的关键点
然后对于大于
1
e
7
1e7
1e7 的关键点,为了防止重复访问,我们采用记忆化,将
x
x
x 这个点的值存在
f
[
n
/
x
]
f[n/x]
f[n/x] 里面。
复杂度大概是
O
(
n
2
3
)
O(n^{\tiny\dfrac{2}{3}})
O(n32)
一道模板题
洛谷
p
4213
p4213
p4213
代码如下
#include <bits/stdc++.h>
#define LL long long
#define N 3000005
using namespace std;
LL z = 1, sphi[N], t, smu[N], f[5005], g[5005];
int maxn = N - 5, cnt, n, p[N], x[N], mu[N], phi[N];
LL getphi(int x){
int i, j;
LL s = 0;
unsigned l, r;
if(x <= maxn) return sphi[x];
if(f[n / x]) return f[n / x];
for(l = 2; l <= x; l = r + 1){
r = x / (x / l);
s = s + (r - l + 1) * getphi(x / l);
}
f[n / x] = z * x * (x + 1) / 2 - s;
return f[n / x];
}
LL getmu(int x){
int i, j;
LL s = 0;
unsigned l, r;
if(x <= maxn) return smu[x];
if(g[n / x]) return g[n / x];
for(l = 2; l <= x; l = r + 1){
r = x / (x / l);
s = s + (r - l + 1) * getmu(x / l);
}
g[n / x] = z - s;
return g[n / x];
}
int main(){
int i, j, T;
mu[1] = phi[1] = 1;
for(i = 2; i <= maxn; i++){
if(!x[i]) x[i] = p[++cnt] = i, mu[i] = -1;
for(j = 1; j <= cnt; j++){
t = z * i * p[j];
if(t > maxn) break;
x[t] = p[j];
if(i % p[j] == 0) break;
mu[t] = -mu[i];
}
}
for(i = 2; i <= maxn; i++){
if(x[i / x[i]] == x[i]) phi[i] = phi[i / x[i]] * x[i];
else phi[i] = phi[i / x[i]] * (x[i] - 1);
}
for(i = 1; i <= maxn; i++) sphi[i] = sphi[i - 1] + phi[i], smu[i] = smu[i - 1] + mu[i];
scanf("%d", &T);
while(T--){
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
scanf("%d", &n);
printf("%lld %lld\n", getphi(n), getmu(n));
}
return 0;
}