zoukankan      html  css  js  c++  java
  • 【ybtoj高效进阶 21266】历经磨难(单调队列优化DP)

    历经磨难

    题目链接:ybtoj高效进阶 21266

    题目大意

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

    思路

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

    首先暴力转移:(f_{i,j}=maxlimits_{i-qleqslant kleqslant 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;
    }
    
  • 相关阅读:
    VS2015, .NET 4.6, C# 6.0, F# 4.0等重量级产品正式上线
    Visual Studio 2015正式发布
    持续集成并不能消除 Bug,而是让它们非常容易发现和改正(转)
    如何用Excel直接查询Oracle中的数据(转)
    HTTP必知必会(转)
    二叉树的友好实现(转)
    TortoiseGit push失败原因小结(转)
    Android
    对JAVA Bean使用PropertyDescriptor反射调用JAVA方法
    关于MSHTML
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21266.html
Copyright © 2011-2022 走看看