poj 3017 Cut the Sequence 不用什么堆和集合直接单调队列解决
来源:互联网 发布:java 线程interrupt 编辑:程序博客网 时间:2024/06/16 18:27
Description
Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of the integers in the part is not greater than a given integer M. You are to find a cutting that minimizes the sum of the maximum integer of each part.
Input
The first line of input contains two integer N (0 < N ≤ 100 000), M. The following line contains N integers describes the integer sequence. Every integer in the sequence is between 0 and 1 000 000 inclusively.
Output
Output one integer which is the minimum sum of the maximum integer of each part. If no such cuttings exist, output −1.
Sample Input
8 172 2 2 8 1 8 2 1
Sample Output
12
Hint
Use 64-bit integer type to hold M.
Source
则必然有dp[i] = min(dp[j] + max(dp[j +1 , a[j + 2].....a[i]))
其中j<= i,j的位置还得满足题目中m 的限制
由于a数组都是大于0的,所以可以发现f必然是非递减的。
设dp[j + 1], dp[j + 2], ...dp[i]中值最大的下标为k
设x为[j + 1,k]的任意一个下标,则a[x],a[x+1],....a[i]的最大值的下标显然也是k了
由dp的非递减性,dp[j+1] + dp[k] <= dp[j+2]+a[k].....<= dp[k - 1] + a[k]
很显然,我们只要取dp[j+1]+a[k]就可以了。
如何维护呢,可以联想到单调队列。
j不用从down(下界)一直枚举到i,我们可以枚举单调队列里的下标。
为什么呢。给出如下证明:
设单调队列里的队头下标为p.值为max,down<=p。那么在down和p之间的元素设为
down<a<b<c<p。那么根据dp的单调性可得dp[down]+max<=dp[a]+max<=dp[b]+max<=dp[c]+max
即下边界元素能保证最优。而j到i的最大值只能在单调队列q[]里取.所以只需遍历q[]里的值
即最大值的可选值就行了。对于每一个最大值的可选值其能产生的最优解为
dp[p]+q[j+1].val.p为上一最大值的下标。
维护一个递减的队列,存的是符合要求的某一段的最大值,
代码如下:
#include <iostream>#include<string.h>#include<stdio.h>#define MIN(a,b) ((a)<(b)?(a):(b))//第一次用感觉还不错using namespace std;struct node{ int val;//存单调队列的值 int id;//存队列元素的下标} q[100100];int a[100100],head,tail,down;int n;__int64 dp[100100],sum,m;int main(){ int i,j,p,flag; while(~scanf("%d%I64d",&n,&m)) { for(i=1; i<=n; i++) scanf("%d",a+i); memset(dp,0,sizeof dp); sum=0; down=1;//down维护 head=tail=0; flag=1; q[tail].val=-1; for(i=1; i<=n; i++)//计算以i结尾的最大值和的最小值 { sum+=a[i]; while(sum>m)//满足和不大于m的区间为low到i。做法很经典。 sum-=a[down++];//减去前面的值使和满足条件。down为左边界。 if(down>i) { flag=0; break; } while(tail>=head&&a[i]>q[tail].val)//将新元素入队 tail--; q[++tail].id=i; q[tail].val=a[i]; while(q[head].id<down)//剔除队列中超过范围的元素 head++; dp[i]=dp[down-1]+q[head].val; for(j=head; j<tail; j++) { p=q[j].id; dp[i]=MIN(dp[i],dp[p]+q[j+1].val);//做法很经典! } } if(flag) printf("%I64d\n",dp[n]); else printf("-1\n"); } return 0;}
- poj 3017 Cut the Sequence 不用什么堆和集合直接单调队列解决
- POJ 3017 Cut the Sequence 单调队列
- poj 3017 Cut the Sequence dp 单调队列+set
- poj 3017 Cut the Sequence(DP+单调队列+set)
- poj 3017 Cut the Sequence(DP+单调队列)
- POJ 3017 Cut the Sequence 单调队列+平衡树
- POJ 3017 Cut the Sequence (单调队列优化DP)
- poj 3017 Cut the Sequence dp+单调队列优化
- poj 3017 Cut the Sequence(dp单调队列优化)
- POJ 3017 Cut the Sequence(dp+单调队列)
- POJ 3017|Cut the Sequence|动态规划|单调队列
- POJ Cut the Sequence 单调队列优化DP入门题
- Poj 3017 Cut the Sequence (DP,单调队列优化,数据结构优化)
- POJ-3017 Cut the Sequence(DP单调队列优化 + 平衡树)
- POJ 3017 Cut the Sequence 【DP+单调队列优化+平衡树】
- [POJ3017] Cut the Sequence && 单调队列
- poj 3017 Cut the Sequence
- POJ 3017 Cut the Sequence
- debug tutorial
- 程序员自我培训指南
- 数据库schema与catalog简介
- hdu2545 树上战争
- c++引用
- poj 3017 Cut the Sequence 不用什么堆和集合直接单调队列解决
- CF 322A Ciel and Dancing 好简单的题。。最喜欢水题了
- 【转】剖析程序的内存布局
- Linux-MySql Cluster配置
- biee 11g连接teradata
- 酱油,简单实现stack
- 【Java笔记】Java开发实战经典 - 第七章
- 概率论01 计数
- poj 1852