1 条题解
-
0
题意
有 个博主,第 个有 和 两个属性。
$$E(S) = \max\left(\min_{i\in S} v_i,\ \min_{i\in S} r_i\right) $$
对于大小为 的子集 ,定义:对每个 ,求所有大小为 的子集的 的平均值,模 。
解法
. 转化求和
固定 ,考虑 的子集。
或 的子集数为:其中:
因为 ,所以:
$$\sum_{|S|=k} E(S) = \sum_{t=1}^{\max V} \left( \binom{a_t}{k} + \binom{b_t}{k} - \binom{c_t}{k} \right) $$. 按值域优化
随 单调不增,只在 的值处变化。
$$\sum_{t=1}^{\max V} \binom{a_t}{k} = \sum_{a=0}^n lenA[a] \cdot \binom{a}{k} $$
对每个 ,计算有多少个 满足 ,记为 。
则:同理对 。
. 计算
通过后缀和得到 ,然后记录变化点。
用差分数组 存储区间长度,最后对每个 求和得到 。. 最终答案
对每个 :
$$\text{sum}_k = \sum_{a} lenA[a]\binom{a}{k} + \sum_{b} lenB[b]\binom{b}{k} - \sum_{c} lenC[c]\binom{c}{k} $$$$avg_k = \frac{\text{sum}_k}{\binom{n}{k}} \pmod{MOD} $$模运算下除法用逆元。
复杂度
- 统计后缀和:
- 计算变化点:
- 枚举所有 : 的总和不超过 ,但由于大多数 ,实际接近 (值域压缩后)。
代码
#include <bits/stdc++.h> using namespace std; const int MOD = 998244353; const int MAXV = 1000000; const int N = 200005; int n; int v[N], r[N]; int cntA[MAXV + 5], cntB[MAXV + 5], cntC[MAXV + 5]; int fact[N], invfact[N]; int ans[N]; int modpow(int a, int e) { int res = 1; while (e) { if (e & 1) res = 1LL * res * a % MOD; a = 1LL * a * a % MOD; e >>= 1; } return res; } void precompute() { fact[0] = 1; for (int i = 1; i <= n; i++) { fact[i] = 1LL * fact[i-1] * i % MOD; } invfact[n] = modpow(fact[n], MOD - 2); for (int i = n-1; i >= 0; i--) { invfact[i] = 1LL * invfact[i+1] * (i+1) % MOD; } } int C(int nn, int kk) { if (kk < 0 || kk > nn) return 0; return 1LL * fact[nn] * invfact[kk] % MOD * invfact[nn - kk] % MOD; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n; for (int i = 1; i <= n; i++) cin >> v[i]; for (int i = 1; i <= n; i++) cin >> r[i]; precompute(); // 统计每个值出现的次数 for (int i = 1; i <= n; i++) { cntA[v[i]]++; cntB[r[i]]++; if (v[i] >= 0 && r[i] >= 0) { cntC[min(v[i], r[i])]++; } } // 后缀和:A_t = 数量大于等于 t 的个数 for (int t = MAXV; t >= 0; t--) { cntA[t] += cntA[t+1]; cntB[t] += cntB[t+1]; cntC[t] += cntC[t+1]; } // 对每个 t,更新所有 k 的贡献 // 使用差分数组优化:对于每个 t,需要将 C(a_t, k) 加到 ans[k] // 由于 a_t 在 t 减少时才会变化,我们可以只处理变化点 vector<int> diffA[N], diffB[N], diffC[N]; int lastA = cntA[MAXV+1], lastB = cntB[MAXV+1], lastC = cntC[MAXV+1]; for (int t = MAXV; t >= 0; t--) { if (cntA[t] != lastA) { diffA[lastA].push_back(t+1); diffA[cntA[t]].push_back(-(t+1)); lastA = cntA[t]; } if (cntB[t] != lastB) { diffB[lastB].push_back(t+1); diffB[cntB[t]].push_back(-(t+1)); lastB = cntB[t]; } if (cntC[t] != lastC) { diffC[lastC].push_back(t+1); diffC[cntC[t]].push_back(-(t+1)); lastC = cntC[t]; } } // 对于每个可能的 cnt 值,处理贡献 for (int a = 0; a <= n; a++) { if (diffA[a].empty() && diffB[a].empty() && diffC[a].empty()) continue; int sumA = 0, sumB = 0, sumC = 0; for (int v : diffA[a]) sumA = (sumA + v) % MOD; for (int v : diffB[a]) sumB = (sumB + v) % MOD; for (int v : diffC[a]) sumC = (sumC + v) % MOD; for (int k = 1; k <= min(n, a); k++) { int waysA = 1LL * sumA * C(a, k) % MOD; int waysB = 1LL * sumB * C(a, k) % MOD; int waysC = 1LL * sumC * C(a, k) % MOD; ans[k] = (ans[k] + waysA + waysB - waysC) % MOD; if (ans[k] < 0) ans[k] += MOD; } } // 计算平均值 for (int k = 1; k <= n; k++) { int inv = modpow(C(n, k), MOD - 2); ans[k] = 1LL * ans[k] * inv % MOD; cout << ans[k] << " \n"[k == n]; } return 0; }
- 1
信息
- ID
- 7156
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 1
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者