题意:给你一个长度为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. Nchan 安装试用(openresty 同时支持)

    备注:        使用nginx最新的源码包(nginx-1.13.6),以及源码安装   1. 下载源码包(nginx+ Nchan) https://nginx.org/download/ng ...

  2. F4NNIU 版本的标准电阻列表(2018-09-29 更新)

    F4NNIU 版本的标准电阻列表(2018-09-29 更新) 值代码 电阻值 格式化值 单位 公差代码 公差 格式化值数字 描述 0RJ 0 0 R J 5% J0000 0R 5% (0RJ) 1 ...

  3. 军哥 LNMP 常见问题

    安装memcached出错: Install memcached...Notice: memcached-1.4.25.tar.gz not found!!!download now...--2016 ...

  4. 初识php,开发环境的配置

    PHP开发环境配置和第一个PHP程序(phpStudy+PhpStorm) 第一步 下载phpStudy 首先,到phpStudy官网上下载最新的phpStudy版本. 第二步 安装phpStudy ...

  5. DeepLearning4J 环境搭建【转】

    深度学习Deeplearning4j eclipse 开发环境搭建 eclipse设置deeplearning4j开发环境:手动添加jar包 https://deeplearning4j.org/cn ...

  6. DBUtils 增删改查例子

    sql CREATE TABLE [dbo].[Person] ( , ) NOT NULL , ) COLLATE Chinese_PRC_CI_AS NULL , [age] [int] NULL ...

  7. 基于Spring Boot和Spring Cloud实现微服务架构

    官网的技术导读真的描述的很详细,虽然对于我们看英文很费劲,但如果英文不是很差,请选择沉下心去读,你一定能收获好多.我的学习是先从Spring boot开始的,然后接触到微服务架构,当然,这一切最大的启 ...

  8. SAE部署Django1.6+MySQL

    [解决]SAE部署Django1.6+MySQL 终于可以舒口气了,今天大部分时间都在搞这个,很是蛋疼,网上资料良莠不齐,我不信这个之前没人做过,但是他们确实分享的不够好. 废话不多说,还是记录一下今 ...

  9. MySQL 存储引擎、锁、调优、失误与事务回滚、与python交互、orm

    1.存储引擎(处理表的处理器) 1.基本操作 1.查看所有存储引擎 mysql> show engines; 2.查看已有表的存储引擎 mysql> show create table 表 ...

  10. 对于Oracle中Number类型的字段映射成Java中的具体类型的问题

    我在Oracle中给一个用户Id字段设置为Number类型,使用JDBC在完成ORM的时候,以为其可以自动转换为Integer,因为我的POJO类id使用的就是Integer.但事实是,我在测试的时候 ...