题目链接:

题目大意(摘自刘汝佳<<算法竞赛入门经典--训练指南>>):F城是由n+1条横向路和m+1条竖向路组成。你的任务是从最南边的路走到最北边的路,使得走过的路上的高兴值和最大(注意,一段路上的高兴值可能是负数)。同一段路不能经过两次,且不能从北往南走,另外,在每条横向路上所花的时间不能超过k。求从南到北走完可以获得的最大高兴值。

分析:用dp[i][j]表示到达编号为(i,j)的路口时所能得到的最大高兴值,则dp[i][j] = max{ dp[i+1][j]; dp[i+1][k] + s[i+1][j]-s[i+1][k], (L[i][j] <= k < j); dp[i+1][k] + s[i+1][k]-s[i+1][j], (j <= k < R[i][j]) };

其中,s[i][j] 表示第i行从第0个路口到第j个路口的高兴值之和,L[i][j]是同一行上能够走到(i,j)位置的最左位置,R[i][j]是同一行上能够走到(i,j)位置的最右位置,这三个量都可以预处理出来。

上述dp的复杂度是O(n^3)的,需要优化,考虑dp[i][j] = max(dp[i+1][k] + s[i+1][j]-s[i+1][k]),i,j固定时,s[i+1][j]为常量,不妨设s[i+1][j] = P, 且令f[k] = dp[i+1][k] - s[i+1][k],则dp[i][j] = max(f[k]) + P,此时就可以用单调队列来维护了,对于每行,从左到右扫描,并维护一个递减的单调对列。具体参看代码。

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 104
#define M 10004 int L[N][M], R[N][M];
int v[N][M], t[N][M];
int n, m, k;
int Q[M];
int f[M], sum[N][M], dp[N][M];
int main()
{
while(~scanf("%d %d %d", &n, &m, &k), n||m||k)
{
for(int i = ; i <= n+; i++)
for(int j = ; j < m; j++)
scanf("%d", &v[i][j]);
for(int i = ; i <= n+; i++)
for(int j = ; j < m; j++)
scanf("%d", &t[i][j]);
for(int i = ; i <= n+; i++)
{
sum[i][] = ;
for(int j = ; j <= m; j++) sum[i][j] = sum[i][j-] + v[i][j-];
}
for(int i = ; i <= n+; i++)
{
L[i][] = , R[i][m] = m;
int cur = , id = ;
for(int j = ; j <= m; j++){
cur += t[i][j-];
while(cur > k) cur -= t[i][id++];
L[i][j] = id;
}
cur = , id = m-;
for(int j = m-; j >= ; j--){
cur += t[i][j];
while(cur > k) cur -= t[i][id--];
R[i][j] = id+;
}
} for(int i = ; i < m+; i++) dp[n+][i] = ;
for(int i = n; i >= ; i--)
{
int head = , rear = ;
for(int j = ; j < m+; j++)
{
f[j] = dp[i+][j] - sum[i+][j];
while(rear < head && Q[rear] < L[i+][j]) rear++;
while(head > rear && f[j] >= f[Q[head-]]) head--;
Q[head++] = j;
dp[i][j] = max(dp[i+][j], sum[i+][j]+f[Q[rear]]);
}
head = , rear = ;
for(int j = m; j >= ; j--)
{
f[j] = dp[i+][j] + sum[i+][j];
while(rear < head && Q[rear] > R[i+][j]) rear++;
while(head > rear && f[j] >= f[Q[head-]]) head--;
Q[head++] = j;
dp[i][j] = max(dp[i][j], f[Q[rear]]-sum[i+][j]);
}
}
int ans = ;
for(int i = ; i < m+; i++) ans = max(ans, dp[][i]);
printf("%d\n", ans);
}
return ;
}

LA 4327 Parade(单调队列优化dp)的更多相关文章

  1. Parade(单调队列优化dp)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    ...

  2. 「学习笔记」单调队列优化dp

    目录 算法 例题 最大子段和 题意 思路 代码 修剪草坪 题意 思路 代码 瑰丽华尔兹 题意 思路 代码 股票交易 题意 思路 代码 算法 使用单调队列优化dp 废话 对与一些dp的转移方程,我们可以 ...

  3. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  4. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  5. hdu3401:单调队列优化dp

    第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...

  6. BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP

    BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP Description 有一排n棵树,第i棵树的高度是Di. MHY要从第一棵树到第n棵树去找他的妹子玩. 如果MHY在 ...

  7. 【单调队列优化dp】 分组

    [单调队列优化dp] 分组 >>>>题目 [题目] 给定一行n个非负整数,现在你可以选择其中若干个数,但不能有连续k个数被选择.你的任务是使得选出的数字的和最大 [输入格式] ...

  8. [小明打联盟][斜率/单调队列 优化dp][背包]

    链接:https://ac.nowcoder.com/acm/problem/14553来源:牛客网 题目描述 小明很喜欢打游戏,现在已知一个新英雄即将推出,他同样拥有四个技能,其中三个小技能的释放时 ...

  9. 单调队列以及单调队列优化DP

    单调队列定义: 其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的. 单调队列的一般应用: 1.维护区间最值 2 ...

随机推荐

  1. oracle expdp/impdp/可传输表空间

    oracle expdp/impdp/可传输表空间/及一些参数 Oracle data pump 导出操作能够将表.索引.约束.权限.PLSQL包.同义词等对象从数据库导出,并将它们保存在一种非文本格 ...

  2. python数据分析入门(一)----安装pandas

    打算入坑, python数据分析 , 所以下载了 <利用python数据分析>的电子书, 影印版 , 14年出版的 , 现在有很多工具对不上号, 但是整体思想还是不变的 , 所以准备工作要 ...

  3. 数据库之DML

    1.表的有关操作: 1.1.表的创建格式: CREATE TABLE IF NOT EXISTS 表名(属性1 类型,属性2 类型,....,属性n 类型):# 标记部分表示可以省略 1.2.表的修改 ...

  4. Java中字母大小写的转换

    例:String str = "AbC"; 把字符串所有字母变成小写: System.out.println(str.toLowerCase()); 把字符串所有字母大写: Sys ...

  5. Mybatis-学习笔记(8)常用的注解

    1.常用的注解. 2.@insert.@delete.@update.@select完成常见的CRUD操作. import java.util.List; import org.apache.ibat ...

  6. Vue 实现手动刷新组件

    Vue 实现手动刷新组件:https://www.jianshu.com/p/742142dc95f3

  7. Java内存结构详解

    Java内存结构详解 Java把内存分成:栈内存,堆内存,方法区,本地方法区和寄存器等. 下面分别介绍栈内存,堆内存,方法区各自一些特性: 1.栈内存 (1)一些基本类型的变量和对象的引用变量都是在函 ...

  8. Linux如何设置在当前目录下打开终端

    转:https://blog.csdn.net/iot_flower/article/details/71189816 1. sudo apt-get install nautilus-open-te ...

  9. [BZOJ3451]Normal(点分治+FFT)

    [BZOJ3451]Normal(点分治+FFT) 题面 给你一棵 n个点的树,对这棵树进行随机点分治,每次随机一个点作为分治中心.定义消耗时间为每层分治的子树大小之和,求消耗时间的期望. 分析 根据 ...

  10. P1168 中位数 堆

    题目描述 给出一个长度为NN的非负整数序列A_iAi​,对于所有1 ≤ k ≤ (N + 1) / 21≤k≤(N+1)/2,输出A_1, A_3, …, A_{2k - 1}A1​,A3​,…,A2 ...