CF 1380G Circular Dungeon

题目描述

http://codeforces.com/contest/1380/problem/G

Solution

我们先转换一下题意

首先,求期望可以看成求和,然后选 $k$ 个假宝箱相当于将前 $k$ 大去掉,剩下的 $n-k$ 个分成 $k$ 段

长度为 $cnt_i$ 的一段的贡献是 $\sum_{i=1}^{cnt_i}i\times a_i$

贪心可得 $a_i$ 递增,然后 $cnt_i$ 的差距不会超过 $1$

具体实现我们可以枚举 $k$,对于一个 $k$,我们每次分配 $k$ 个即可

时间复杂度 $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
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <stack>
#include <cstring>
#define maxn 300010
#define ll long long
using namespace std;

const int p = 998244353;

ll pow_mod(ll x, ll n) {
ll s = 1;
for (; n; n >>= 1) {
if (n & 1) s = s * x % p;
x = x * x % p;
}
return s;
}

int n, a[maxn];

ll s[maxn];

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

cin >> n; ll inv = pow_mod(n, p - 2);
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + n + 1, greater<int>());
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
for (int k = 1; k <= n; ++k) {
ll ans = 0;
for (int i = k + 1, j = 1; i <= n; i += k, ++j)
ans = (ans + j * (s[min(i + k - 1, n)] - s[i - 1])) % p;
ans = ans * inv % p;
cout << (ans + p) % p << " ";
}
return 0;
}