我困炸了,一个月没有六点起过床了。
统计总贡献不好统计,考虑把贡献拆开统计。发现统计每个数出现次数还是不好统计,那就直接把数也拆开。
对于每一个 \(i\),统计 \(\ge i\) 的数有多少个,加起来就是总和了。
设 \(\ge i\) 的数有 \(c\) 个。发现,如果一开始的 \(n-x+1\) 大于 \(c\) 个,那么如果选一个 \(\ge i\) 的数会使 \(c + 1\),否则 \(c\) 数量不变。同理,如果一开始的 \(n-x+1\) 小于等于 \(c\) 个,那么如果选一个 \(\ge i\) 的数 \(c\) 不变,否则 \(c - 1\)。最后 \(c\) 到 \(n-x+1\) 的时候不变,于是就取个 \(\max / \min\)。
枚举选了多少个 \(\ge i\) 的数,那么就可以计算最后的 \(c\) 等于多少与选择的方案数,乘起来统计答案。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 4005, P = 998244353;
int qpow(int a, int b) {
int ans = 1;
while (b) {
if (b & 1) ans = 1ll * ans * a % P;
a = 1ll * a * a % P;
b >>= 1;
}
return ans;
}
int n, m, k, x;
int a[MAXN];
int fac[MAXN], inv[MAXN];
int C(int n, int m) {
if (n < 0 || m < 0 || n < m) return 0;
return 1ll * fac[n] * inv[m] % P * inv[n - m] % P;
}
int main() {
scanf("%d%d%d%d", &n, &m, &k, &x);
fac[0] = 1;
for (int i = 1; i <= k; i++) {
fac[i] = 1ll * fac[i - 1] * i % P;
}
inv[k] = qpow(fac[k], P - 2);
for (int i = k; i >= 1; i--) {
inv[i - 1] = 1ll * inv[i] * i % P;
}
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
sort(a + 1, a + 1 + n);
int ans = 0;
for (int i = 1; i <= m; i++) {
int c = n - (lower_bound(a + 1, a + 1 + n, i) - a) + 1;
if (c <= n - x + 1) {
for (int j = 0; j <= k; j++) {
ans = (ans + 1ll * C(k, j) * qpow(m - i + 1, j) % P * qpow(i - 1, k - j) % P * min(n - x + 1, c + j)) % P;
}
} else {
for (int j = 0; j <= k; j++) {
ans = (ans + 1ll * C(k, j) * qpow(m - i + 1, j) % P * qpow(i - 1, k - j) % P * max(n - x + 1, c - (k - j))) % P;
}
}
}
printf("%d\n", ans);
return 0;
}
标签:Queue,int,inv,1ll,Priority,ge,MAXN,ans,ARC139D
From: https://www.cnblogs.com/apjifengc/p/17068714.html