1. 程式人生 > 其它 >CF1542D Priority Queue 題解

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;
}