Luogu6222 「P6156 简单题」加强版(加强版)

题意:给出 ,对于 ,分别求 ,时限


的答案。令 ,用 来拆解

。线性筛出 后,对 进行差分,可以发现是 的部分和。

预处理 之后

已经可以整除分块,但我们不满足于这个形式,进行差分

,则 是积性函数,用“快速卷积性函数”可做到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <algorithm>
#include <cstdio>

using uint = unsigned int;
const int MaxN = 10050000;

uint powM(uint a, int t) {
uint ret = 1;
while (t) {
if (t & 1)
ret *= a;
a *= a;
t >>= 1;
}
return ret;
}

uint S[MaxN*2], f[MaxN];
int p[MaxN/7], totP;
bool flag[MaxN*2];

void sieve(int n, int k) {
S[1] = f[1] = flag[1] = 1;
for (int i=1; i<=2*n; i++) {
if (!flag[i]) {
p[++totP] = i;
S[i] = powM(i, k);
if (i<=n)
f[i] = 1;
}
for (int j = 1; j<=totP; j++) {
int t = p[j] * i;
if (t>2*n) break;
flag[t] = true;
S[t] = S[i] * S[p[j]];
if (i%p[j]==0) break;
if (t<=n)
f[t] = f[i];
}
}
p[++totP] = 2*n+1;
for (int i=1; i<=2*n; i++)
S[i] += S[i-1];
for (uint i = 1; i<=n; i++) {
if (f[i])
f[i] = i;
S[i] = S[2*i] + S[2*i-1] - 2*S[i];
}
for (int i = 1; p[i] <= n; i++) {
static uint sav[MaxN];
std::copy(S+1, S+n/p[i]+1, sav+1);
for (long long d=p[i]; d<=n; d*=p[i]) {
uint buf = (f[d] - f[d/p[i]]) * powM(d, k);
for (int t=1; t*d<= n; t++)
S[t*d] += sav[t]*buf;
}
}
for (int i=1; i<=n; i++)
S[i] += S[i-1];
}

int main() {
int T, N, K;
scanf("%d%d%d", &T, &N, &K);
sieve(N, K);
while (T--) {
scanf("%d", &N);
printf("%u\n", S[N]);
}
return 0;
}