题目大意:让你求
∑
i
=
1
n
f
(
i
)
\sum_{i = 1} ^ nf(i)
∑i=1nf(i),
f
(
i
)
f(i)
f(i)为
i
i
i 的次大质因数。
这道题的解法基于min_25筛的算法过程:
min_25筛不仅可以筛一些积性函数前缀和,也能筛一些非积性函数前缀和,它的算法思想都是将贡献分成两部分:质数部分和合数部分。
令
S
(
n
,
j
)
S(n,j)
S(n,j) 表示 最小质因子大于
p
j
p_j
pj的函数前缀和
对于质数部分通常都会转化成积性函数,然后筛
g
(
n
,
p
)
g(n,p)
g(n,p)。
对于合数部分,算法流程是枚举最小质因子以及最小质因子的幂次
p
k
e
p_k^e
pke,然后用
S
(
⌊
n
p
k
e
⌋
,
k
)
S(\lfloor\frac{n}{p_k^e}\rfloor,k)
S(⌊pken⌋,k)转移,无论是筛
g
(
n
,
j
)
g(n,j)
g(n,j) 还是筛
S
(
n
,
j
)
S(n,j)
S(n,j) 都是基于 dp的思想,当筛的函数是积性函数时:合数部分可以提取
f
(
p
k
e
)
f(p_k^e)
f(pke),变成:
∑
k
=
j
+
1
,
p
k
<
n
∑
e
=
1
,
p
k
e
≤
x
f
(
p
k
e
)
∗
(
S
(
⌊
n
p
k
e
⌋
,
k
)
+
[
e
>
1
]
)
\sum_{k =j + 1,p_k<\sqrt n}\sum_{e = 1,p_k^e\leq x}f(p_k^e)*(S(\lfloor\frac{n}{p_k^e}\rfloor,k) + [e >1])
k=j+1,pk<n∑e=1,pke≤x∑f(pke)∗(S(⌊pken⌋,k)+[e>1])
这题是非积性函数,仍然可以用min_25筛枚举最小质因子的思想。
首先根据题意,质数部分贡献为0。
合数部分:枚举 最小质因子
p
k
p_k
pk时,
p
k
p_k
pk有贡献当且仅当除掉
p
k
e
p_k^e
pke后的数是质数 或为 1,若不是质数,那么可以对
⌊
n
p
k
e
⌋
\lfloor\frac{n}{p_k^e}\rfloor
⌊pken⌋进行递归继续拆解,也就是
S
(
⌊
n
p
k
e
⌋
,
j
+
1
)
S(\lfloor\frac{n}{p_k^e}\rfloor,j + 1)
S(⌊pken⌋,j+1),而
p
k
p_k
pk 的贡献 =
p
k
∗
(
∑
i
=
1
⌊
n
p
k
e
⌋
[
i
∈
p
r
i
m
e
,
i
>
=
p
k
]
)
p_k * (\sum_{i = 1}^{\lfloor\frac{n}{p_k^e}\rfloor}[i \in prime,i >= p_k])
pk∗(∑i=1⌊pken⌋[i∈prime,i>=pk]),括号内的部分也就是
[
1
,
⌊
n
p
k
e
⌋
]
[1,\lfloor\frac{n}{p_k^e}\rfloor]
[1,⌊pken⌋]内大于等于
p
k
p_k
pk 的质数的个数,这个显然可以用min_25筛,筛出
[
1
,
n
]
[1,n]
[1,n]的质数个数。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;
bool ispri[maxn];
int tot,num;
ll pri[maxn],w[maxn],g[maxn],sqr,n;
ll id1[maxn],id2[maxn];
void sieve(int n) {
ispri[0] = ispri[1] = true;
num = 0;
for(int i = 2; i <= n; i++) {
if(!ispri[i]) pri[++num] = i;
for(int j = 1; j <= num && i * pri[j] <= n; j++) {
ispri[i * pri[j]] = true;
if(i % pri[j] == 0) break;
}
}
}
ll S(ll n,ll x,ll y) {
if(pri[y] > x) return 0;
ll res = 0;
for(int i = y + 1; i <= num && 1ll * pri[i] * pri[i] <= x; i++) {
for(ll e = 1,pe = pri[i]; pe * pri[i] <= x; pe = pe * pri[i],e++) {
ll t = x / pe;
ll k = t <= sqr ? id1[t] : id2[n / t];
res += S(n,x / pe,i) + pri[i] * (g[k] - i + 1);
}
}
return res;
}
ll solve(ll n) {
tot = 0;
sqr = sqrt(n);
for(ll i = 1,j; i <= n; i = j + 1) {
j = n / (n / i);
w[++tot] = n / i;
g[tot] = n / i - 1;
if(n / i <= sqr) id1[n / i] = tot;
else id2[j] = tot;
}
for(int i = 1; i <= num; i++) {
for(int j = 1; j <= tot && pri[i] * pri[i] <= w[j]; j++) {
ll t = w[j] / pri[i];
ll k = t <= sqr ? id1[t] : id2[n / t];
g[j] -= g[k] - (i - 1);
}
}
return S(n,n,0);
}
ll l,r;
int main() {
sieve(maxn - 10);
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(r) - solve(l - 1));
return 0;
}