题目链接:

题目大意(摘自刘汝佳<<算法竞赛入门经典--训练指南>>):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. Octavia 的 HTTPS 与自建、签发 CA 证书

    目录 文章目录 目录 Octavia 为什么需要自建 CA 证书? GenerateServerPEMTask CertComputeCreate Amphora Agent AmphoraAPICl ...

  2. Delphi XE2 之 FireMonkey 入门(40) - 控件基础: TMemo

    Delphi XE2 之 FireMonkey 入门(40) - 控件基础: TMemo 值得注意的变化: 1.其父类 TScrollBox 的许多特性也很有用处, 如:   Memo1.UseSma ...

  3. JavaSE部分1.Java基础

    1.为什么重写equals()还要重写hashcode()?  (equals()和hashCode()是java Object中两个基本方法) 首先equals与hashcode间的关系是这样的: ...

  4. laravel 多字段登录

    protected function validateChinaPhoneNumber($number) { return preg_match('/^1[34578]\d{9}$/', $numbe ...

  5. HTML5——拖放 地理定位 视频 音频 新的input类型

    拖放 ————>   设置元素为可拖放 拖动什么 放到何处 进行放置 实例[来回拖放] 地理定位 使用地理定位 处理错误和拒绝 在地图中显示结果 基于脚本的交互式地图 给定位置的信息 用户移动时 ...

  6. 操作系统(3)实验相关原理——bootloader启动uCore

    x86启动顺序 CS+EIP决定启动地址. CS部分后面又4个0,相当于是左移了4位.总之就是要让CS左移4位之后加上EIP来得到要跳转的地址. 0x7c00地方开始的512字节的内容就是bootlo ...

  7. PSP周总结03

      周日 周一 周二 周三 周四 周五 周六 所花时间 120 150 190 180 180 300 代码量 159 372 博客量 1 了解的知识点 阅读构建之法 软件工程概论 阅读构建之法 图书 ...

  8. 【Linux开发】V4L2应用程序框架

    V4L2应用程序框架 V4L2较V4L有较大的改动,并已成为2.6的标准接口,函盖video\dvb\FM...,多数驱动都在向V4l2迁移.更好地了解V4L2先从应用入手,然后再深入到内核中结合物理 ...

  9. python字符串-方法

    一.1. upper()作用:将字符串中字符转换为大写 In [17]: spam Out[17]: 'hello,world' In [18]: print(spam.upper()) HELLO, ...

  10. <<用法

    数据移位运算符,左移几位,如:x=i<<4;就是将i的值左移4位(放大2的4次方)后,赋给x,若i=2,则X=32.