题意:给你一个长度为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. piezo film 压电相关信息记录 (2018-05-04 更新)

    piezo film 压电相关信息记录 起因需要使用 Piezo 做一些设计 http://www.te.com.cn/chn-zh/videos/transportation/piezo-film- ...

  2. bzoj 1101 [POI2007]Zap——反演

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1101 #include<cstdio> #include<cstring& ...

  3. 8.Python编写登录接口

    1.python需安装flask,在命令行窗口输入:pip3 install flask 2.代码如下所示: from flask import Flask,request,jsonify,sessi ...

  4. thinkphp3.2.3版本在windows本地apache环境运行正常,上传到centos服务器apache环境中出现:thinkphp 上传根目录不存在!请尝试手动创建:uploads/

    thinkphp 上传根目录不存在!请尝试手动创建:uploads/  ,是根目录下uploads权限问题,我把uploads权限改成了775,就可以上传图片了.     chmod -R 775 u ...

  5. python3 内存管理

    怎么查找哪里存在内存泄露呢?武器就是两个库:gc.objgraph pip install psutil pip install objgraphpip install -U memory_profi ...

  6. Linux之安装软件

    1.  下载获得redis-3.0.4.tar.gz后将它放入我们的Linux目录/opt 2. 在SecureCRT界面上点SecureFX图标 在本地窗口中找到要上传的文件 在要上传的文件上点右键 ...

  7. Java基础--NIO

    NIO库在JDK1.4中引入,它以标准Java代码提供了高速的,面向块的IO,弥补了之前同步IO的不足. 缓冲区Buffer Buffers是一个对象,包含了一些要写入或读出的数据.在面向流的IO模型 ...

  8. solr核心概念、配置文件

    Document Document是Solr索引(动词,indexing)和搜索的最基本单元,它类似于关系数据库表中的一条记录,可以包含一个或多个字段(Field),每个字段包含一个name和文本值. ...

  9. Tomcat配置远程调试

    ===========方法1================================ tomcat7 :catalina.bat jpda start,调试端口默认为8000 ======== ...

  10. 老师金角大王的BLOG

    首页: http://www.cnblogs.com/alex3714/ python3专题: http://www.cnblogs.com/alex3714/category/770733.html