牛客 contest 42400E NTT

题目描述

https://ac.nowcoder.com/acm/contest/42400/E

简要题意:现在有 $T$ 组询问,每次询问给定 $n$,求所有长度为 $n$ 的每个位置是 $[1,n]$ 的序列的价值和,定义一个序列的价值和为 $\sum_{i=k}^{\min(k,n-1)+n-1}\frac{lcm(i-k+1,n)}{k+1}$,其中 $k$ 是该序列中未出现的数的种数

$n,T\le 10^6$

Solution

简单转化后容易得到 $ans=(\sum_{i=1}^n[i,n])\times \sum_{i=1}^n\frac{1}{n-i+1}\binom{n}{i}nx^i^i$,前面两个东西无关,我们先考虑化简前面那个东西,考虑莫比乌斯反演的部分,容易得到前面那个东西为 $\sum_{i=1}^n[i,n]=n\sum_{d|n}\frac{n}{d}\frac{[n=d]+\varphi(\frac{n}{d})}{2}$,这个可以 $O(n\log n)$ 预处理,我们考虑化简后半部分

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
#include <iostream>
#define maxn 1000010
using namespace std;

const int p = 998244353;
inline int add(int x, int y) { return (x += y) >= p ? x - p : x; }
inline int mul(int x, int y) { return 1ll * x * y % p; }
inline int add(initializer_list<int> lst) { int s = 0; for (auto t : lst) s = add(s, t); return s; }
inline int mul(initializer_list<int> lst) { int s = 1; for (auto t : lst) s = mul(s, t); return s; }
int pow_mod(int x, int n) {
int s = 1;
for (; n; n >>= 1, x = mul(x, x))
if (n & 1) s = mul(s, x);
return s;
}

int pri[maxn], phi[maxn], cnt, f[maxn]; bool isp[maxn];
void init_isp(int n) {
phi[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!isp[i]) pri[++cnt] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt && i * pri[j] <= n; ++j) {
isp[i * pri[j]] = 1;
if (i % pri[j] == 0) {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
phi[i * pri[j]] = phi[i] * (pri[j] - 1);
}
} const int inv2 = pow_mod(2, p - 2);
for (int i = 1; i <= n; ++i)
for (int j = i; j <= n; j += i) f[j] = add(f[j], mul({ (i == j) + phi[j / i], j / i, inv2 }));
for (int i = 1; i <= n; ++i) f[i] = mul(f[i], i);
}

int n;

void work() {
cin >> n;
cout << mul(pow_mod(n + 1, n - 1), f[n]) << "\n";
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T; init_isp(1000000);
while (T--) work();
return 0;
}