题意:给你一个长度为n的数列,你需要把这个数列分成几段,每段的和不超过m,问各段的最大值之和的最小值是多少?

思路:dp方程如下:设dp[i]为把前i个数分成合法的若干段最大值的最小值是多少。dp转移比较显然,dp[i] = min{dp[j] + max(a[j + 1] , a[j + 2] ... + a[i])}, 其中a[j + 1] + a[j + 2] +... + a[i] <= m;这个dp转移是O(n^2)的,我们需要用单调队列优化。单调队列维护的是a值单调递减的序列(要保证与i位置的区间和小于等于m)而单调队列的对头不一定是最优的。需要找出单调队列中的最小值,这个需要用堆或者线段树来维护一下。dp[i]的转移分为两种,一种是j + 1 到i的和正好小于m的这种转移,另一种是单调队列中的最小值,两者取min就是当前状态的最小值。

这题有两个点需要注意。1:若j在单调队列里,那么max(a[j + 1] , a[j + 2] ... + a[i])是单调队列里的下一个值。2:因为max(a[j + 1] , a[j + 2] ... + a[i])这个值是有可能随i的变化而变化,所以,如果用堆去维护单调队列中的值, 需要对每个j记录一下最新的max(a[j + 1] , a[j + 2] ... + a[i]), 不能直接扔到堆里就完事了。。。或者,使用pbds中的堆,它支持对堆中元素的修改,然而POJ不支持pbds。。。。

一般堆的代码:

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define LL long long
#define pii pair<int, int>
#define lowbit(x) (x << 1)
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
#define db double
#define pli pair<LL, int>
using namespace std;
const int maxn = 100010;
struct node {
LL val;
int pos;
bool operator < (const node & rhs) const {
return val > rhs.val;
}
};
priority_queue<node> Q;
LL dp[maxn], a[maxn];
int q[maxn];
bool v[maxn];
LL val[maxn];
LL sum[maxn];
void change(LL x, int y) {
Q.push((node){x, y});
val[y] = x;
}
int main() {
int n;
LL m;
scanf("%d%lld", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
int l = 1, r = 1, ans = 0, pos = 0;
dp[1] = a[1];
q[1] = 1;
if(a[1] > m) ans = -1;
for (int i = 2; i <= n; i++) {
while(sum[i] - sum[pos] > m) pos++;
if(pos == i) {
ans = -1;
break;
}
while(l <= r && sum[i] - sum[q[l] - 1] > m) {
v[q[l]] = 1;
l++;
}
while(l <= r && a[q[r]] <= a[i]) {
v[q[r]] = -1;
r--;
}
if(l <= r)
change(dp[q[r]] + a[i], q[r]);
q[++r] = i;
dp[i] = dp[pos] + a[q[l]];
while(Q.size() && (v[Q.top().pos] == 1 || val[Q.top().pos] != Q.top().val)) {
Q.pop();
}
if(Q.size()) {
dp[i] = min(dp[i], Q.top().val);
}
}
if(ans == -1) {
printf("%d\n", ans);
} else {
printf("%lld\n", dp[n]);
}
}

pb_ds的代码(应该是对的吧)

#include <bits/stdc++.h>
#define LL long long
#define pii pair<int, int>
#define lowbit(x) (x << 1)
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
#define db double
#define pli pair<LL, int>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
const int maxn = 100010;
struct node {
LL val;
int pos;
bool operator < (const node & rhs) const {
return val > rhs.val;
}
};
typedef __gnu_pbds::priority_queue<node> Heap;
Heap Q;
Heap::point_iterator id[maxn];
LL dp[maxn], a[maxn];
int q[maxn];
bool v[maxn];
LL sum[maxn];
void change(LL x, int y) {
if(id[y] != 0)Q.modify(id[y], (node){x, y});
else id[y] = Q.push((node){x, y});
}
int main() {
int n, m;
//freopen("17.in", "r", stdin);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
int l = 1, r = 1, ans = 0, pos = 0;
dp[1] = a[1];
q[1] = 1;
if(a[1] > m) ans = -1;
for (int i = 2; i <= n; i++) {
while(sum[i] - sum[pos] > m) pos++;
if(pos == i) {
ans = -1;
break;
}
while(l <= r && sum[i] - sum[q[l] - 1] > m) {
v[q[l]] = 1;
l++;
}
if(l > r) {
ans = -1;
break;
}
while(l <= r && a[q[r]] <= a[i]) {
v[q[r]] = 1;
r--;
}
// Q.push(make_pair(dp[pos] + a[i], a[q[l]]));
// printf("%d\n", Q.size());
if(l <= r)
change(dp[q[r]] + a[i], q[r]);
q[++r] = i;
dp[i] = dp[pos] + a[q[l]];
while(Q.size() && v[Q.top().pos]) {
id[Q.top().pos] = 0;
Q.pop();
}
if(Q.size()) {
//printf("%lld %d\n", Q.top().val, Q.top().pos);
dp[i] = min(dp[i], Q.top().val);
}
}
for (int i = 1; i <= n; i++)
printf("%d %lld\n", i, dp[i]);
if(ans == -1) {
printf("%d\n", ans);
} else {
printf("%lld\n", dp[n]);
}
}

  

POJ 3017 DP + 单调队列 + 堆的更多相关文章

  1. 刷题总结——Cut the Sequence(POJ 3017 dp+单调队列+set)

    题目: Description Given an integer sequence { an } of length N, you are to cut the sequence into sever ...

  2. POJ-3017 Cut the Sequence DP+单调队列+堆

    题目链接:http://poj.org/problem?id=3017 这题的DP方程是容易想到的,f[i]=Min{ f[j]+Max(num[j+1],num[j+2],......,num[i] ...

  3. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)

    DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...

  4. 习题:烽火传递(DP+单调队列)

    烽火传递[题目描述]烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有n个烽火台,每个烽火台 ...

  5. DP+单调队列 codevs 1748 瑰丽华尔兹(还不是很懂具体的代码实现)

    codevs 1748 瑰丽华尔兹 2005年NOI全国竞赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题解       题目描述 Descripti ...

  6. (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列

    Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. ...

  7. 3622 假期(DP+单调队列优化)

    3622 假期 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 黄金 Gold 题目描述 Description 经过几个月辛勤的工作,FJ决定让奶牛放假.假期可以在1-N天内任意选择 ...

  8. 【POJ 2823】Sliding Window(单调队列/堆)

    BUPT2017 wintertraining(16) #5 D POJ - 2823 题意 给定n,k,求滑窗[i,i+k-1]在(1<=i<=n)的最大值最小值. 题解 单调队列或堆. ...

  9. POJ - 3162 Walking Race 树形dp 单调队列

    POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...

随机推荐

  1. vault key 管理工具

    Vault is a tool for securely accessing secrets. A secret is anything that you want to tightly contro ...

  2. Mathtype启动失败与Microsoft公式编辑器Equation的问题处理案例

    最近写毕业论文需要使用Mathtype,安装成功后,启动Word,使用Mathtype,出现各种问题. 遇到的问题: 1.弹出“用于创建对象的程序是Equation.您的计算机尚未安装此程序.若要编辑 ...

  3. 进程间通信IPC之--无名管道(pipe)和有名管道(fifo)(转)

     进程间通信IPC之--无名管道(pipe)和有名管道(fifo) 2012-01-17 22:41:20 分类: C/C++ 每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中 ...

  4. Android UI一些技巧

    (1)去掉EditText的背景颜色  android:background="@null" (2)ListView 修改某行的值,因为一些功能逻辑,需要修改ListView某行的 ...

  5. python接口自动化19-requests-toolbelt处理multipart/form-data

    requests-toolbelt 1.官方文档地址:requests-toolbelt官方文档 2.环境安装 pip install requests-toolbelt multipart/form ...

  6. Mac OS Virtualbox 倒入 ova 镜像文件

    原文:https://www.zhihu.com/question/40785995 ------------------ 自己亲测 --------------------- 把 windows 系 ...

  7. iRedMail的搭建过程记录

    iRedMail的搭建和注意事项 经过一段时间的折腾,终于将iRedMail搭建起来了,下面介绍一下搭建的过程,以及注意事项. 注意事项:  1. iRedMail不支持重复安装,如果安装错误,请重置 ...

  8. 超详细的php用户注册页面填写信息完整实例(附源码)

    这篇文章主要介绍了一个超详细的php用户注册页面填写信息完整实例,内容包括邮箱自动匹配.密码强度验证以及防止表单重复等,小编特别喜欢这篇文章,推荐给大家. 注册页面是大多数网站必备的页面,所以很有必要 ...

  9. 5月22日上课笔记-js属性选择器、过滤选择器、鼠标事件

    一.属性选择器 [attr] 包含属性 [attr=value] 属性值 [attr!=value] 属性值不等于value [attr^=value] 属性值以value开头 [attr$=valu ...

  10. zabbix-3.2.1监控nginx-1.11.5

    声明参考地址:http://www.ttlsa.com/zabbix/zabbix-monitor-nginx-performance/ 1.zabbix需要监控nginx,则nginx需要配置ngx ...