【题解】【CF1542D Priority Queue】
Analysis
首先想到对每个数计算有多少种子序列使得最终集合包含这个数,用方案数乘上这个数再累加求和即可。
所以设f[i][j]表示前i个位置,目前有j个小于等于a[p]的数的方案数,
- i<p
f[0][0]=1;
(1) a[i]=='-'
f[i][j]=f[i-1][j]+f[i-1]j+1
f[i][0]=f[i-1][1]+f[i-1][0]2;
(2) a[i]<=a[p]
f[i][j]=f[i-1][j-1]+f[i-1][j],j>0;
f[i][0]=f[i-1][0];
(3) a[i]>a[p]
f[i][j]=f[i-1][j]2; - f[p][j]=f[p-1][j];
对于i>p的情况有两点与i<p不同,一个是当a[i]='-'时,f[i][0]只能累加一个f[i-1][0],因为再选一个'-'号的话就会删掉a[p]了。
第二是当a[i]=a[p]时要把他当成大于a[p]的情况,否则会算重。
那为什么这样是对的呢?可以这么想:对于删除操作,如果有多个最小值,则优先删除先加入的值,显然这不会影响答案。
总结
一开始分析的时候在想怎么分别计算这个数左右两边的方案数再乘起来,但其实直接做一个从左到右的序列dp即可。
还有注意算重的情况,可以考虑将重复的地方进一步分类,取其中一种特殊的来计算,对应本题就是将删除相同的值看做删除最先加入的。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int x=0,w=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') {w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=~(x-1);
if(x>9) write(x/10);
putchar('0'+x%10);
}
const int N=505,mod=998244353;
int n,a[N],f[N][N],ans;
signed main()
{
n=read();char op[2];
for(int i=1;i<=n;++i)
{
scanf("%s",op);
if(op[0]=='-') a[i]=-1;
else a[i]=read();
}
for(int p=1;p<=n;++p)
{
if(a[p]>0)
{
memset(f,0,sizeof f);
f[0][0]=1;
for(int i=1;i<p;++i) {
if(a[i]<0){
for(int j=i;j;--j) f[i][j]=f[i-1][j]+f[i-1][j+1],f[i][j]%=mod;
f[i][0]=f[i-1][1]+f[i-1][0]*2,f[i][0]%=mod;
}
else if(a[i]<=a[p]){
for(int j=i;j;--j) f[i][j]=f[i-1][j]+f[i-1][j-1],f[i][j]%=mod;
f[i][0]=f[i-1][0];
}
else for(int j=i;j>=0;--j) f[i][j]=f[i-1][j]*2%mod;
}
for(int j=0;j<p;++j) f[p][j]=f[p-1][j];
for(int i=p+1;i<=n;++i)
{
if(a[i]<0){
for(int j=i;j;--j) f[i][j]=f[i-1][j]+f[i-1][j+1],f[i][j]%=mod;
f[i][0]=f[i-1][1]+f[i-1][0],f[i][0]%=mod;
}
else if(a[i]<a[p]){
for(int j=i;j;--j) f[i][j]=f[i-1][j]+f[i-1][j-1],f[i][j]%=mod;
f[i][0]=f[i-1][0];
}
else for(int j=i;j>=0;--j) f[i][j]=f[i-1][j]*2%mod;
}
int sum=0;for(int i=0;i<=n;++i) sum+=f[n][i],sum%=mod;
ans+=sum*a[p]%mod;ans%=mod;
}
}
write(ans);
return 0;
}

浙公网安备 33010602011771号