CF1542D Priority Queue 题解
一、题目:
二、思路:
这道题很明显是一道 DP 题。
考虑计算某个 + x
对答案的贡献。也就是说,我们的目标是对于每个 + x
,求出有多少个子序列满足经过一番操作之后,这个 \(x\) 会被统计到答案中。
对于固定的、处于位置 \(p\) 的一个 + x
,考虑 DP。设 \(dp[i,j]\) 表示考虑了前 \(i\) 位,有 \(j\) 个比 \(x\) 小的方案数。
-
若第 \(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\) 没有影响。 -
若第 \(i\) 位是正数而且比 \(x\) 大,则 \(dp[i,j]=dp[i-1,j]\times 2\)。选和不选都不会使得 \(j\) 改变。
-
若第 \(i\) 位是正数而且比 \(x\) 小,则
\[dp[i,j]= \begin{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\n", ans);
return 0;
}