「解题报告」ARC139D Priority Queue 2

我困炸了,一个月没有六点起过床了。

统计总贡献不好统计,考虑把贡献拆开统计。发现统计每个数出现次数还是不好统计,那就直接把数也拆开。

对于每一个 \(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;
}
posted @ 2023-01-27 10:59  APJifengc  阅读(40)  评论(1编辑  收藏  举报