2020 Multi-University Training Contest 6 (杭电多校) 1007
问:
答:
先令 \(g = \gcd(a_1, a_2 \cdots , a_x), F(x) = f(x)x\)。
由莫比乌斯反演有:
(具体怎么计算 \(H\) 后文有)则 \(F = H * 1\)。
那么原式子等价于:
那么,令 \(S(d) = \sum_{i = 1}^d i^k, T(d) = H(d) \times d^{kx}\),那么上式等价于:
显然,\(S(d)\) 是可以预处理出来的,且套用数论分块就能求出上面的式子。那么现在的关键就是怎么求 \(H(d)\) 。
由于
注意到这是个积性函数,那么我们可以考虑如何用线性筛来求得上面的函数。
1.当 \(x\) 是质数,也就是 \(x = p\) 时
$$
H(p) = 1 \mu^2(1)\mu(p) + p\mu^2(p)\mu(1) = p - 1
$$
2.当 \(x\) 不是质数,但 \(x = a \times p\),且 \(a\) 与 \(p\) 互质时,由积性函数有
$$
H(a \times p) = H(a) \times H(p)
$$
3.当 \(x\) 不是质数,但 \(x = a \times p\),且 \(a\) 与 \(p\) 不互质时,令 \(a = b \times p^{t - 1}\),其中 \(b\) 与 \(p\) 互质,那么就有
$$
H(a \times p) = H(b \times p^t) = H(b) \times H(p^t) \quad (t \ge 2)
$$
注意到
$$
H(p^t) = \sum_{d | pt}d\mu2(d)\mu(\frac{p^t}{d}) = \sum_{t_1 = 0}^t p{t_1}\mu2(p{t_1})\mu(p) \quad (t_1 + t_2 = t)
$$
中,当且仅当 \(t_1 = t_2 = 1\quad (t = 2)\) 时,\(H(p^t) = -p\),其他时候 \(H(p^t) = 0\)
所以,利用线性筛,能在 \(O(n\log n)\) 的时间内预处理出 \(H(x), T(x), S(x)\)。然后每次询问,利用数论分块求和。总的时间复杂度为:\(O(n\log n + T \sqrt n)\)
参考代码:
#include <bits/stdc++.h>
#define lowbit(x) ((x) & (-x))
#define mem(i, a) memset(i, a, sizeof(i))
#define sqr(x) ((x) * (x))
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
typedef long long ll;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 7;
using namespace std;
int h[maxn], prime[maxn], tmp[maxn];
int mod = 1e9 + 7;
int sum[maxn], T, k, x;
bool check[maxn];
int tot = 0;
ll qpow(ll a, ll n) {
ll ans = 1;
for (a %= mod; n; n >>= 1) {
if (n & 1) ans = a * ans % mod;
a = a * a % mod;
}
return ans;
}
void init(int n) {
h[1] = 1;
tot = 0;
for (int i = 2; i <= n; i++) {
if (!check[i]){
prime[tot++] = i;
h[i] = i - 1;
}
for (int j = 0; j < tot && prime[j] * i <= n; j++) {
check[i * prime[j]] = 1;
if (i % prime[j] == 0) {
int cnt = 1, x = i;
while (x % prime[j] == 0) {
cnt++;
x /= prime[j];
}
if (cnt == 2)
h[i * prime[j]] = (-1ll * prime[j] * h[x] % mod + mod) % mod;
else
h[i * prime[j]] = 0;
break;
} else {
h[i * prime[j]] = 1ll * h[i] * h[prime[j]] % mod;
}
}
}
for (int i = 1; i <= n; i++) sum[i] = (sum[i - 1] + qpow(i, k)) % mod;
for (int i = 1; i <= n; i++){
tmp[i] = h[i] * qpow(i, 1ll * k * x %(mod - 1)) % mod;
tmp[i] = (tmp[i] + tmp[i - 1]) % mod;
sum[i] = qpow(sum[i], x);
}
}
int main(void) {
#ifdef ljxtt
freopen("data.in", "r", stdin);
#endif
scanf("%d%d%d", &T, &k, &x);
init(maxn - 1);
while (T--) {
int n;
scanf("%d", &n);
ll ans = 0;
for(int i = 1, r; i <= n; i = r + 1){
r = min(n, n / (n / i));
ans = (ans + 1ll * (tmp[r] - tmp[i - 1] + mod) % mod * sum[n / i] % mod) % mod;
}
ans = (ans % mod + mod) % mod;
printf("%lld\n", ans);
}
return 0;
}