CF1542D Priority Queue 题解

经过感性剖析,他显然是个 \(dp\)

假定我们找到了处于位置 \(t\) 的一个 \(+x\)\(dp[i][j]\) 表示到第 \(i\) 位为止,集合中有 \(j\) 个数 \(<=x\) 的方案数。
操作序列是数组 \(a\) ,我们的目的是要让我们选定的这个到最后并对答案产生贡献,我们分成以下几种情况讨论

\(i<t\)

若这一位是 \(-\) ,那么 \(dp[i][j] = dp[i-1][j] + dp[i-1][j+1]\) 如果不选,他就是上一位直接继承下来
但如果选,他就相当于删去了一个数,也就是说原来是 \(j+1\)

并且特别的,若 $ j=0 $ ,需要在上式的基础上再加 $ dp[i-1][0] $

当 $ i=t $ 时

根据我们给的定义,这里是必选的 \(dp[i][j]=dp[i][j-1]\)

\(i>t\)

其实和 \(i<t\) 差不多
若是 \(-\) ,不存在特殊情况,因为此时我们找的那个 \(x\) 已经在序列中了

若是 \(+x\) 大于我们找的那个值
那么 \(dp[i][j]=dp[i-1][j]*2\)

如果小于把 \(j+1\) 就行了

最后统计答案

code:


#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
const int mod=998244353;
const int maxn=610;
struct node{
	int x;
	bool plus;//判断是哪种操作 
}a[maxn];
int dp[maxn][maxn];
signed main()
{
	cin>>n;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		
		char ch;
		cin>>ch;
		if(ch=='+')
		{
			a[i].plus=true;
			cin>>a[i].x;
		}
		else a[i].plus=false;
	}
	for(int t=1;t<=n;t++)
	{
		if(a[t].plus)
		{	
			memset(dp,0,sizeof(dp));//每一次dp都要清零 
			int at=a[t].x;
			dp[0][0]=1;//初始状态 
			for(int i=1;i<t;i++)//i<t的情况 
			{
				if(!a[i].plus)//如果第i位是- 
				{
					for(int j=0;j<=n;j++)
					{
						dp[i][j]+=dp[i-1][j+1];//累加选的方案 
						dp[i][j]%=mod;
					}
					for(int j=0;j<=n;j++)
					{
						dp[i][j]+=dp[i-1][j];//累加不选的方案 
						dp[i][j]%=mod;
					}
					dp[i][0]=dp[i][0]+dp[i-1][0];//特殊情况
					dp[i][0]%=mod; 
/*
这是因为会有两种情况:

1. 根据题意,若没有 $+x$ ,就不管他

2. 若删去的数比 $x$ 大,也是 $dp[i-1][0]$

所以要多加一遍
*/
				}
				else//如果第i位是+x 
				{
					if(a[i].x>at)
					{
						for(int j=0;j<=n;j++)
						{
							dp[i][j]+=(dp[i-1][j]*2)%mod;//选与不选均不会对j有影响 
							dp[i][j]%=mod;
						}
					}
					else
					{
						for(int j=0;j<=n;j++)
						{
							dp[i][j]+=dp[i-1][j]%mod;//不选 
							dp[i][j]%=mod;
						}
						for(int j=1;j<=n;j++)
						{
							dp[i][j]+=dp[i-1][j-1]%mod;//选 
							dp[i][j]%=mod;
						}
					}
				}
			}
			for(int i=0;i<=n;i++)//i=t的情况 
			{
				dp[t][i]=dp[t-1][i];
			}
			for(int i=t+1;i<=n;i++)//i>t的情况 
			{
				if(!a[i].plus)
				{
					for(int j=0;j<=n;j++)
					{
						dp[i][j]+=dp[i-1][j];//不选 
						dp[i][j]%=mod;
					}
					for(int j=0;j<=n;j++)
					{
						dp[i][j]+=dp[i-1][j+1];//选 
						dp[i][j]%=mod;
					}
				}
				else
				{
					if(a[i].x>=at)
					{
						for(int j=0;j<=n;j++)
						{
							dp[i][j]+=dp[i-1][j]*2%mod;//同上一种情况 
							dp[i][j]%=mod;
						}
					}
					else
					{
						for(int j=0;j<=n;j++)
						{
							dp[i][j]+=dp[i-1][j]%mod;//同上一种情况 
							dp[i][j]%=mod;
						}
						for(int j=1;j<=n;j++)
						{
							dp[i][j]+=dp[i-1][j-1]%mod;
							dp[i][j]%=mod;
						}
					}
				}
			}
			int tmp=0;
			for(int i=0;i<=n;i++)//计算总的贡献 
			{
				tmp+=(dp[n][i]*a[t].x)%mod;
				tmp%=mod;
			}
			ans+=tmp;
			ans%=mod;
		}
		
	}
	cout<<ans;
}
posted @ 2021-10-06 16:08  Konjac-Simit  阅读(71)  评论(0)    收藏  举报