D. Priority Queue(Codeforces Round #729 (Div. 2))

D. Priority Queue

链接

题意

题意为给你n个操作模拟一个优先队列,其中 - 表示弹出队列中最小的元素,+ 表示向队列中加入一个整数x;
你可以任选操作,但相对顺序不能改变,对于每一个操作组合,求出最后队列中剩余数的和作为这个组合的最终结果,答案为所有操作组合的最终结果的和

思路

对于每个加入的数x考虑其对答案的贡献,即求出其出现次数y,则其对答案的贡献为x*y

对于当前下标i(因为考虑贡献,所以忽略弹出操作),j遍历所有下标,k表示在1到j中小于a[i]的数量(即子序列的长度),dp[j][k]表示在上述情况下a[i]的出现次数。
转移情况如下:(a[i]表示第i次操作加入的元素,若为弹出操作则为-1)

dp的起始状态是:dp[0][0] = 1
基础转移方程:dp[j][k] = dp[j][k] + dp[j-1][k],因为1到j中小于a[i]的数量为k的出现次数一定来源于1到j-1中小于a[i]的数量为k的出现次数;

a[j]==-1时,dp[j][k] = dp[j][k] + dp[j-1][k+1];
如果i == j,则直接跳过;
如果i != j

如果k == 0的话,则dp[j][k] = dp[j][k] + dp[j-1][k];
如果a[j] < a[i],并且k != 0,则dp[j][k] = dp[j][k] + dp[j-1][k-1];
如果a[j] == a[i],此时需要考虑j和i的关系,因为当大小相等时会按照相对顺序进行弹出,所以要保证j < i,这样相当于a[j] < a[i]的情况,所以仍是dp[j][k] = dp[j][k] + dp[j-1][k-1];
剩余情况(即a[j] > a[i] 或者 a[j] == a[i] && j > i),此时因为这类情况不会影响a[i]的出现,所以为: dp[j][k] = dp[j][k] + dp[j-1][k],相当于做了两遍基础转移方程,因为此时a[j]的选与不选在a[i]出现的情况下不会产生影响。

在每一轮结束后,更新答案,即加上此时a[i]的贡献(a[i] * y),y为出现次数,

y=j=0ndp[n][j]()

Code

/*---------------------------------------------------------------
            ∧_∧
      ∧_∧  (´<_` )  
     ( ´_ゝ`) /  ⌒i     
    /   \     | |
    /   / ̄ ̄ ̄ ̄/  |
  __(__ニつ/     _/ .| .|____
     \/____/ (u ⊃
--------------------------------------------------------------*/
#include<bits/stdc++.h>
#define IO  ios::sync_with_stdio(false);cin.tie(0)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define req(i,a,b) for(int i=a;i>=b;i--)
#define pb push_back		
#define fi first
#define se second
#define PI pair<int,int>
#define PII pair<ll,PI>

using namespace std;

typedef long long ll;
const int N=1e5+7;
const ll mod=998244353;
ll a[507];
ll dp[507][507];
int main()
{
	IO; 
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
	{
		char x;
		cin >> x;
		if (x == '-')
		{
			a[i] = -1;
		}else{
			cin >> a[i];
		}
	}ll ans = 0;
	for (int i = 1; i <= n; ++i)
	{
		memset(dp,0,sizeof(dp));
		dp[0][0] = 1;
		if (a[i] == -1)
		{
			continue;
		}
		for (int j = 1; j <= n; ++j)
		{
			for (int k = 0; k <= j; ++k)
			{
				dp[j][k] += dp[j-1][k];
				dp[j][k] %= mod;
				if (a[j] == -1)
				{
					dp[j][k] += dp[j-1][k+1];
					dp[j][k] %= mod;
					if (k == 0 && j < i)
					{
						dp[j][k] += dp[j-1][k];
						dp[j][k] %= mod;
					}
				}
				else{
					if (i == j)
					{
						continue;
					}
					if (a[j] < a[i] || (a[j] == a[i] && j < i))
					{
						if (k != 0)
						{
							dp[j][k] += dp[j-1][k-1];
							dp[j][k] %= mod;
						}
					}else {
						dp[j][k] += dp[j-1][k];
						dp[j][k] %= mod;
					}
				}
			}
		}
		for (int j = 0; j <= n; ++j)
		{
			ans += a[i] * dp[n][j] % mod;
			ans %= mod;
		}
	}cout << ans << endl;
	return 0;
} 
posted @   !^^!  阅读(171)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· 探秘 MySQL 索引底层原理,解锁数据库优化的关键密码(下)
· 大模型 Token 究竟是啥:图解大模型Token
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
阅读排行:
· BotSharp 5.0 MCP:迈向更开放的AI Agent框架
· 分享 3 款基于 .NET 开源且免费的远程桌面工具
· 在线聊天系统中的多窗口数据同步技术解密
· 2025,回顾出走的 10 年
· 【保姆级教程】windows 安装 docker 全流程
点击右上角即可分享
微信分享提示