POJ 3017 DP + 单调队列 + 堆
题意:给你一个长度为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 + 单调队列 + 堆的更多相关文章
- 刷题总结——Cut the Sequence(POJ 3017 dp+单调队列+set)
题目: Description Given an integer sequence { an } of length N, you are to cut the sequence into sever ...
- 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] ...
- [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)
DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...
- 习题:烽火传递(DP+单调队列)
烽火传递[题目描述]烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有n个烽火台,每个烽火台 ...
- DP+单调队列 codevs 1748 瑰丽华尔兹(还不是很懂具体的代码实现)
codevs 1748 瑰丽华尔兹 2005年NOI全国竞赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Descripti ...
- (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列
Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. ...
- 3622 假期(DP+单调队列优化)
3622 假期 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 黄金 Gold 题目描述 Description 经过几个月辛勤的工作,FJ决定让奶牛放假.假期可以在1-N天内任意选择 ...
- 【POJ 2823】Sliding Window(单调队列/堆)
BUPT2017 wintertraining(16) #5 D POJ - 2823 题意 给定n,k,求滑窗[i,i+k-1]在(1<=i<=n)的最大值最小值. 题解 单调队列或堆. ...
- POJ - 3162 Walking Race 树形dp 单调队列
POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...
随机推荐
- 编写浏览器和Node.js通用的JavaScript模块
长期以来JavaScript语言本身不提供模块化的支持, ES6中终于给出了 from, import等关键字来进行模块化的代码组织. 但CommonJS.AMD等规范已经被广为使用,如果希望你的Ja ...
- HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)
版权声明:欢迎关注我的博客.本文为博主[炒饭君]原创文章,未经博主同意不得转载 https://blog.csdn.net/a1061747415/article/details/25471349 P ...
- 13.Python接口自动化测试 -- 豆瓣
1.代码如下所示: import requests,unittest import json import HTMLTestRunner class TestDouBan(unittest.TestC ...
- eclipse Mars(4.5.2)安装pydev后不出现
一.环境 windows 7 64bit eclipse 4.5.2 pydev jdk7u55 二.安装步骤 1. 安装JDK eclipse依赖于java环境,所以需要安装java运行环境JRE. ...
- idea maven 打包 引用本地jar
1将本地jar包导入到mvn本地库 mvn install:install-file -Dfile=/Users/liuqiang/Documents/gmpl/gmpl-server/lib/ali ...
- hadoop Shuffle Error OOM错误分析和解决
在执行Reduce Shuffle的过程中,偶尔会遇到Shuffle Error,但是重启任务之后,Shuffle Error会消失,当然这只是在某些特定情况下才会报出来的错误.虽然在每次执行很短的时 ...
- SVN的学习
SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于CVS,它采用了分支管理系统,它的设计目标就是取代CVS 为什么需要SVN 通常软件开发由多人协作开发,如果对代码文件.配置文 ...
- 【BZOJ】1833: [ZJOI2010] count 数字计数(数位dp)
题目 传送门:QWQ 分析 蒟蒻不会数位dp,又是现学的 用$ dp[i][j][k] $ 表示表示长度为i开头j的所有数字中k的个数 然后预处理出这个数组,再计算答案 代码 #include < ...
- 构建:vue项目配置后端接口服务信息
背景 vue-cli脚手架生成的webpack标准模板项目 HTTP库使用axios 一.开发环境跨域与API接口服务通信 整体思路: 开发环境API接口请求baseURL为本地http://loca ...
- input标签存在的兼容问题?
当input标签在type为text时,在Firefox和Safari中的默认高度为22像素(包括上下边框)宽度为146像素(包括左右边框),而在IE中的默认高度为24像素,而宽度却和Firefox和 ...