ICode9

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

【ybtoj高效进阶 21266】历经磨难(单调队列优化DP)

2021-10-27 07:35:26  阅读:181  来源: 互联网

标签:进阶 sta0 sta1 int ybtoj l1 801 DP 10001


历经磨难

题目链接:ybtoj高效进阶 21266

题目大意

给你 n 个事件,每个事件有收益,时间,然后你可以选不超过 k 个事件,要求你选的两个相邻的事件相差的时间要在 p~q 之间,然后每个事件还有一个数值 di,如果你选出来的事件中相邻的两个有因子 t,那贡献就要减去 z。
然后问你最大贡献是多大。

思路

考虑进行 DP,设 \(f_{i,j}\) 为前 \(i\) 个磨炼,用了 \(j\) 个的。

首先暴力转移:\(f_{i,j}=\max\limits_{i-q\leqslant k\leqslant i-p}\{f_{k,j}\}+c_i\)(这里是先不管 \(z\),即 \(z=0\))

不难看出区间固定长度,就是滑动窗口,用单调队列优化即可。

接着考虑 \(z\) 的各种情况。
那我们考虑到就是要相邻的两个都有 \(t\) 的因子,也就是都是 \(t\) 的倍数。
那就弄两个 \(f\),分别表示最后一个是 \(t\) 的倍数或者不是 \(t\) 的倍数的最大贡献。

然后就弄一下也可以转移了。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 1e9

using namespace std;

int n, k, t, p, q, z;
int c[10001], d[10001];
int f[10001][801], ans;
int sta0[801][10001], sta1[801][10001];
int l0[801], l1[801];

int main() {
//	freopen("trouble.in", "r", stdin);
//	freopen("trouble.out", "w", stdout);
	
	scanf("%d %d %d %d %d %d", &n, &k, &t, &p, &q, &z);
	for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
	for (int i = 1; i <= n; i++) scanf("%d", &d[i]);
	
	for (int i = 1; i <= k; i++) {
		l0[i] = l1[i] = 1;
//		sta0[i][++sta0[i][0]] = 0; sta1[i][++sta1[i][0]] = 0;
	}
	memset(f, -0x7f, sizeof(f));
	f[0][0] = 0; d[0] = k + 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= k; j++) {
			if (i >= p) {//分别维护两个单调队列
				if (d[i - p] % t == 0) {
					while (l0[j] <= sta0[j][0] && f[i - p][j - 1] >= f[sta0[j][sta0[j][0]]][j - 1]) sta0[j][0]--;
					sta0[j][++sta0[j][0]] = i - p;
				}
				else {
					while (l1[j] <= sta1[j][0] && f[i - p][j - 1] >= f[sta1[j][sta1[j][0]]][j - 1]) sta1[j][0]--;
					sta1[j][++sta1[j][0]] = i - p;
				}
			}
			while (l0[j] <= sta0[j][0] && i - sta0[j][l0[j]] > q) l0[j]++;
			while (l1[j] <= sta1[j][0] && i - sta1[j][l1[j]] > q) l1[j]++;
			
			if (d[i] % t == 0) {//DP
				f[i][j] = max((l1[j] <= sta1[j][0]) ? f[sta1[j][l1[j]]][j - 1] : -INF, (l0[j] <= sta0[j][0]) ? f[sta0[j][l0[j]]][j - 1] - z : -INF) + c[i];
				ans = max(ans, f[i][j]);
			}
			else {
				f[i][j] = max((l1[j] <= sta1[j][0]) ? f[sta1[j][l1[j]]][j - 1] : -INF, (l0[j] <= sta0[j][0]) ? f[sta0[j][l0[j]]][j - 1] : -INF) + c[i];
				ans = max(ans, f[i][j]);
			}
		}
	}
	
	printf("%d", ans);
	
	return 0;
}

标签:进阶,sta0,sta1,int,ybtoj,l1,801,DP,10001
来源: https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21266.html

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

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

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

ICode9版权所有