「LOJ 6053」简单的函数-ExtendedEratosthenesSieve

一个函数 $f(x)$,它满足:

  1. $f(1) = 1$。
  2. $f(p ^ c) = p \oplus c$($p$ 为质数,$\oplus$ 表示异或)。
  3. $f(ab) = f(a)f(b)$($a$ 与 $b$ 互质)。

求 $\sum\limits_{i = 1} ^ n f(i) \bmod 1000000007$。

链接

LOJ 6053

题解

扩展埃拉托色尼筛法中的几个部分就是题面中所定义好的了,由于 $f(p) = p \ \mathrm{xor} \ 1$,所以我们求出 $p ^ 1, p ^ 0$ 相减后要加回多减掉的 $p = 2$ 时的情况就可以了。

注意预处理时候的取模不要问我是怎么知道的

代码

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* Copyright (c) 2017-2018, xehoth
* All rights reserved.
* 「LOJ 6053」简单的函数 24-01-2018
* Extended Eratosthenes Sieve
* @author xehoth
*/
#include <bits/stdc++.h>
namespace {
const int MOD = 1e9 + 7;
typedef unsigned int uint;
typedef unsigned long long ulong;
long long n;
uint M;
inline int add(const int x, const int v) {
return x + v >= MOD ? x + v - MOD : x + v;
}
inline int dec(const int x, const int v) {
return x - v < 0 ? x - v + MOD : x - v;
}
std::vector<int> pre[2], suc[2], primes;
int rec(ulong res, int last, int mul) {
int t =
dec(res > M ? suc[1][n / res] : pre[1][res], pre[1][primes[last] - 1]);
int ret = (ulong)t * mul % MOD;
for (int i = last, p; i < (int)primes.size(); i++) {
p = primes[i];
if ((ulong)p * p > res) break;
ulong q = p, nres = res;
for (int nmul, e = 1; q * p <= res; q *= p) {
nmul = (ulong)mul * (p ^ e) % MOD;
ret = add(ret, rec(nres /= p, i + 1, nmul));
ret = add(ret, (ulong)mul * (p ^ (++e)) % MOD);
}
}
return ret;
}
inline int solve(const ulong n) {
M = sqrt(n);
pre[0].resize(M + 1);
pre[1].resize(M + 1);
suc[0].resize(M + 1);
suc[1].resize(M + 1);
primes.reserve(M + 1);
for (uint i = 1; i <= M; i++) {
pre[0][i] = i - 1;
pre[1][i] = (i * (i + 1ull) / 2 - 1) % MOD;
const ulong t = (n / i) % MOD;
suc[0][i] = t - 1;
suc[1][i] = (t * (t + 1ull) / 2 - 1) % MOD;
}
for (uint p = 2, end; p <= M; p++) {
if (pre[0][p] == pre[0][p - 1]) continue;
primes.push_back(p);
const ulong q = (ulong)p * p, m = n / p;
const int pcnt = pre[0][p - 1], psum = pre[1][p - 1];
end = std::min<long long>(M, n / q);
for (uint i = 1, w = M / p; i <= w; i++) {
suc[0][i] = dec(suc[0][i], dec(suc[0][i * p], pcnt));
suc[1][i] =
dec(suc[1][i], dec(suc[1][i * p], psum) * (ulong)p % MOD);
}
for (uint i = M / p + 1; i <= end; i++) {
suc[0][i] = dec(suc[0][i], dec(pre[0][m / i], pcnt));
suc[1][i] =
dec(suc[1][i], dec(pre[1][m / i], psum) * (ulong)p % MOD);
}
for (uint i = M; i >= q; i--) {
pre[0][i] = dec(pre[0][i], dec(pre[0][i / p], pcnt));
pre[1][i] =
dec(pre[1][i], dec(pre[1][i / p], psum) * (ulong)p % MOD);
}
}
primes.push_back(M + 1);
for (uint i = 1; i <= M; i++) {
pre[1][i] = (i >= 2 ? add(2, dec(pre[1][i], pre[0][i]))
: dec(pre[1][i], pre[0][i]));
suc[1][i] = (n >= i * 2 ? add(2, dec(suc[1][i], suc[0][i]))
: dec(suc[1][i], suc[0][i]));
}
return n > 1 ? 1 + rec(n, 0, 1) : 1;
}
} // namespace
int main() {
std::cin >> n;
std::cout << solve(n);
}
分享到