POJ 3017 Cut the Sequence (单调队列优化DP)

POJ 3017 Cut the Sequence (单调队列优化DP)

ACM

题目地址:

POJ 3017 Cut the Sequence

题意:

将一个由N个数组成的序列划分成若干段,要求每段数字的和不超过M,求【每段的最大值】的和 的最小的划分方法,输出这个最小的和。

分析:

方程是:dp[i] = min(dp[j]+maxsum[j+1][i])

但复杂度n*n太高,需要优化。

可以用单调队列+BST优化,其实只需要维护每一段的最大值。

看了这篇题解的:http://blog.csdn.net/muye67/article/details/5999033

代码:

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        3017.cpp
*  Create Date: 2014-09-17 21:41:41
*  Descripton:  dp
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define repf(i,a,b) for(int i=(a);i<=(b);i++)
typedef long long ll;

const int N = 1e5+10;

ll n, m, arr[N], sum[N];
ll dp[N], q[N];
int front, rear;

int main() {
	ios_base::sync_with_stdio(0);

	while (cin >> n >> m) {
		sum[0] = 0;
		repf (i, 1, n) {
			cin >> arr[i];
			sum[i] = sum[i - 1] + arr[i];
		}

		front = rear = 1;
		q[rear] = 1;
		bool flag = arr[1] > m;
		int t = 0;
		dp[0] = 0;
		dp[1] = arr[1];
		repf (i, 2, n) {
			while (i > t && sum[i] - sum[t] > m)
				t++;
			if (i == t) {
				flag = 1;
				break;
			}
			while (front <= rear && arr[i] >= arr[q[rear]])
				rear--;
			q[++rear] = i;
			while (front <= rear && sum[i] - sum[q[front] - 1] > m)
				front++;
			dp[i] = dp[t] + arr[q[front]];
			repf (j, front, rear - 1)
				dp[i] = min(dp[i], dp[q[j]] + arr[q[j + 1]]);
		}
		cout << (flag ? -1 : dp[n]) << endl;
	}
	return 0;
}
时间: 2024-10-22 19:30:15

POJ 3017 Cut the Sequence (单调队列优化DP)的相关文章

$Poj3017\ Cut\ The\ Sequence$ 单调队列优化$DP$

Poj   AcWing Description 给定一个长度为N的序列 A,要求把该序列分成若干段,在满足“每段中所有数的和”不超过M的前提下,让“每段中所有数的最大值”之和最小. N<=105,M<=1011,0<Ai<=106 Sol 一篇比较清楚的题解 $OvO$ $F[i]$表示把前$i$个数分成若干段,满足每段中所有数之和不超过$M$的前提下,各段的最大值之和的最小值 不难推出转移方程: 但是直接枚举$j$的做法是$O(N^{2})$的,显然过不去,还要优化. DP转移

poj 3017 Cut the Sequence

poj 3017 Cut the Sequence 单调队列 题意是:把一个 长度 为 n 的 数列 分成任意份,使每一份的和不超过m,求每一份的最大值的和,使和最小 动态规划方程 是 f [i] = f[j] + max{ f[j+1] , f[j+2] , f[i] }; 朴素的算法是 O(n^2); 用 单调队列 表示一个递减 的 队列 ,则 不需要 求 每块区域的最大值 哎哎哎……不知道怎么说 #include <iostream> #include <cstdio> #i

POJ 3926 Parade 单调队列优化DP

来源:http://poj.org/problem?id=3926 题意:行n <= 100, 列m <= 10000,类似于数字三角形,一个人要从底下往上走,每层中可以左右走,但选定方向不能回头(向左不能再向右),每经过一段获得该段的一个值,并走了该段的距离,在同一层走的距离不能超过k.问走到最顶头,获得的总值最大是多少. 分析:dp[i][j]表示走到第i行第j列,获得的值最大为多少.则dp[i][j] = max(dp[i+1][p] + sum(p to j)),sum(p to j)

POJ 1742 Coins 多重背包单调队列优化

http://poj.org/problem?id=1742 题意: 很多硬币,有价值和数量,给出一个上限,问上限内有多少种钱数可以由这些硬币组成. 分析: 好像是楼教主男人八题之一.然后学多重背包单调队列优化时看了别人的程序..所以后来写了就1A了=.= 前一篇小小总结了一下多重背包单调队列优化(http://www.cnblogs.com/james47/p/3894772.html),这里就不写了. 1 #include<cstdio> 2 #include<cstring>

POJ 1821 Fence(单调队列优化DP)

题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂完前j个位置的最大收益. 然后转移考虑 第i个人可以不刷.dp[i][j]=dp[i-1][j]; 第j个木板可以不刷dp[i][j]=dp[i][j-1]; 然后当c[i].s<=j<=s[i]+l[i]-1时 dp[i][j]=p[i]*j+max(dp[i-1][k]-p[i]*k)其中j-

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

Tyvj1305最大子序和(单调队列优化dp)

描述 输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大. 例如 1,-3,5,1,-2,3 当m=4时,S=5+1-2+3=7当m=2或m=3时,S=5+1=6 输入格式 第一行两个数n,m第二行有n个数,要求在n个数找到最大子序和 输出格式 一个数,数出他们的最大子序和 测试样例1 输入 6 4 1 -3 5 1 -2 3 输出 7 备注 数据范围:100%满足n,m<=300000 是不超过m,不是选m个!!!!! /* 单调队列优化dp 单调队列维护的是前

bzoj1855: [Scoi2010]股票交易--单调队列优化DP

单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w-1][k]+k*Ap[i]的单调性即可 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 const int maxn = 2010; 6 int

1855: [Scoi2010]股票交易[单调队列优化DP]

1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status][Discuss] Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=