ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「题解」Codeforces 1542D Priority Queue

2021-07-05 09:32:36  阅读:364  来源: 互联网

标签:Queue ch return int 题解 Priority template dp mod


考虑一个数对答案的贡献,我们想要的是有替当前这个数 pop 的替死鬼,那么可以设计一个 dp:设 \(f_{i,j}\) 为当前考虑 \(a_x\) 在原序列选到 \(i\),共有 \(j\) 个替死鬼。注意到由于可以是非连续的子序列,所以每个 \(f_{i,j}\) 转移可以从 \(<i\) 的所有 \(k\),所有的 \(f_{k,j'}\) 转移而来。\(j'\) 是固定的,具体选哪个我们后面再说。这样子一次 \(f_{i,j}\) 就可以通过处理出对于每个 \(j\),预处理出所有 \(f_{k,j}\) 的前缀和,做到 \(\mathcal{O}(1)\) 转移。

那么如何选择 \(j'\) ?注意到如果当前 \(a_i=a_x\),没有定义谁先 pop,所以钦定遇到此类情况,且 \(i<x\) 的时候 \(a_i\) 才能当 \(a_x\) 的替死鬼。由于相等时弹出的数之间是没有区分的,但只有一种弹出的方案,所以给他加上区分仍然只有一种弹出方案,这样钦定是正确的。

综上所述,可以简单地设出一个 \(f_{i,j}\) 的 dp,来得到 \(a_x\) 对答案贡献了多少次,一共枚举 \(\mathcal{O}(n)\) 个 \(x\),一次 dp \(\mathcal{O}(n^2)\),复杂度为 \(\mathcal{O}(n^3)\)。

简单来讲,我们做的是考虑一个数对答案贡献的次数,基于“替死鬼”的贪心设计一个 dp。

详细 dp 方程见代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
typedef long long ll;
const ll mod = 998244353;
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T> T Add(T x, T y) { return (x + y >= mod) ? (x + y - mod) : (x + y); }
template <typename T> T Mul(T x, T y) { return x * y % mod; }
template <typename T>
T &read(T &r) {
	r = 0; bool w = 0; char ch = getchar();
	while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
	while(ch >= '0' && ch <= '9') r = (r << 3) + (r <<1) + (ch ^ 48), ch = getchar();
	return r = w ? -r : r;
}
ll qpow(ll x, ll y) {
	ll sumq = 1;
	while(y) {
		if(y&1) sumq = sumq * x % mod;
		x = x * x % mod;
		y >>= 1;
	} return sumq;
}
const int N = 510;
int n, a[N];
ll s[N], f[N][N], ans;
void dp(int p) {
	s[0] = 1;
	for(int i = 1; i <= n; ++i) {
		if(i == p) continue ;
		for(int j = 0; j <= i; ++j) {
			if(a[i] == 1 && !j) { f[i][j] = 0; continue ; }
			if(a[i] != -1) {
				if(a[i] < a[p] || (a[i] == a[p] && i < p)) f[i][j] = s[j-1];
				else f[i][j] = s[j] % mod;
			}
			else f[i][j] = Add(s[j+1], (j==0 && i < p) ? s[0] : 0ll);
		}
		for(int j = 0; j <= i; ++j) s[j] = Add(s[j], f[i][j]);
	}
}
signed main() {
	read(n);
	for(int i = 1; i <= n; ++i) {
		char ch; std::cin >> ch;
		if(ch == '+') read(a[i]);
		else a[i] = -1;
	}
	for(int i = 1; i <= n; ++i)
		if(a[i] != -1) {
			for(int j = 1; j <= n; ++j) s[j] = 0;
			dp(i);
			ll sum = 0;
			for(int i = 0; i <= n; ++i) sum = Add(sum, s[i]);
			ans = Add(ans, sum * a[i] % mod);
		}
	printf("%lld\n", ans);
	return 0;
}

标签:Queue,ch,return,int,题解,Priority,template,dp,mod
来源: https://www.cnblogs.com/do-while-true/p/14970876.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有