CF1542D Priority Queue 题解

一、题目:

洛谷原题

codeforces原题

二、思路:

这道题很明显是一道 DP 题。

考虑计算某个 + x 对答案的贡献。也就是说,我们的目标是对于每个 + x,求出有多少个子序列满足经过一番操作之后,这个 (x) 会被统计到答案中。

对于固定的、处于位置 (p) 的一个 + x,考虑 DP。设 (dp[i,j]) 表示考虑了前 (i) 位,有 (j) 个比 (x) 小的方案数。

  1. 若第 (i) 位是 -,则 (dp[i,j]=dp[i-1,j]+dp[i-1,j+1])

    这里需要着重强调,如果 (i<p)(j=0),那么 (dp[i,0]) 还要再加上 (dp[i-1,0])。原因是这样的,如果 (i<p),那么根据题目的约定,如果此时 (T) 是空的,那么我们什么也不做,所以,此时选上 - 号不会使得 (j) 变小。如果此时 (T) 中还有比 (x) 大的数,那 - 号也只会消去比 (x) 大的数,同样对 (j) 没有影响。

  2. 若第 (i) 位是正数而且比 (x) 大,则 (dp[i,j]=dp[i-1,j] imes 2)。选和不选都不会使得 (j) 改变。

  3. 若第 (i) 位是正数而且比 (x) 小,则

    [dp[i,j]= egin{cases} dp[i-1,j] &j=0\ dp[i-1,j]+dp[i-1,j-1] &j>0 end{cases} ]

细心的同学可能会发现,那第 (i) 位如果和 (x) 相等怎么办?

我的处理方法是这样的,为了避免重复计算,强制规定,如果 (i<p),那么就把它归到第 3 种情况中;如果 (i>p),那么就把它归到第 2 种情况中。

三、代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
#define FILEIN(s) freopen(s, "r", stdin)
#define FILEOUT(s) freopen(s, "w", stdout)
#define mem(s, v) memset(s, v, sizeof s)

inline int read(void) {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return f * x;
}

const int MAXN = 505, MOD = 998244353;

int n, a[MAXN];
long long dp[MAXN][MAXN];

int main() {
    n = read();
    for (int i = 1; i <= n; ++ i) {
        char op[3]; scanf("%s", op);
        if (*op == '-')
            a[i] = -1;
        else
            a[i] = read();
    }
    long long ans = 0;
    for (int p = 1; p <= n; ++ p) {
        if (a[p] < 0) continue;
        int x = a[p];
        mem(dp, 0); dp[0][0] = 1;
        for (int i = 1; i <= n; ++ i) {
            if (i == p) {
                memcpy(dp[i], dp[i - 1], sizeof dp[i]);
                continue;
            }
            for (int j = 0; j <= n; ++ j) {
                if (a[i] < 0) {
                    dp[i][j] = (dp[i - 1][j] + dp[i - 1][j + 1]) % MOD;
                    if (j == 0 && i < p) (dp[i][j] += dp[i - 1][j]) %= MOD;
                }
                else if (a[i] < x || (a[i] == x && i < p)){
                    dp[i][j] = dp[i - 1][j];
                    if (j > 0) (dp[i][j] += dp[i - 1][j - 1]) %= MOD;
                }
                else
                    dp[i][j] = 2 * dp[i - 1][j] % MOD;
            }
        }

        long long sum = 0;
        for (int j = 0; j <= n; ++ j)
            (sum += dp[n][j]) %= MOD;
        (ans += sum * x % MOD) %= MOD;
    }
    printf("%lld
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/little-aztl/p/14968449.html