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

题目链接:http://poj.org/problem?id=3017

题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小

分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m

这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =)

然后是优化了,首先当然是要优化一个最大值的队列,使得这个队列的队首元素的到当前位置的和不超过m,

这样一个可行解就是,f[ i ]=f[b[ i ]-1]+a[ q[ l ]](即队首元素的值),

这并不是最优解,所以还要找到队列中的最优解,一个可能的最优解只能是这样的

f[ q[ j ] ]+ a[ q[j +1 ]],也就是 a[ j ] 要大于后面的数,

很显然,如果a[ j ]小于后面的数,那么我们就可以将 a[ j ] 划分到后面去,而取得更优解

这里涉及的这个找最优解问题;

AC代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 using namespace std;
 6 typedef long long LL;
 7 const int N = 100020;
 8 LL num[N];
 9 LL sum[N];
10 LL f[N];
11 int q[N];
12 int main() {
13     int n, i, j, st, ed, p;
14     LL m;
15     while(~scanf("%d%I64d", &n, &m)) {
16         memset(f, -1, sizeof(f));
17         st = 0, ed = -1;
18         p = 1;
19         sum[0] = 0;
20         f[0] = 0;
21         for(i = 1; i <= n; ++i) {
22             scanf("%I64d", num + i);
23             sum[i] = sum[i-1] + num[i];// 统计前n项的和
24             if(st > ed) {
25                 st = 0, ed = -1;
26                 q[++ed] = i;
27             }
28             while(st <= ed && num[i] >= num[q[ed]])   --ed;//单调队列优化
29             q[++ed] = i;
30             while(sum[i] - sum[p-1] > m)    ++p;
31             while(st <= ed && p > q[st])    st++;//单调队列里面保存的数已经被删除,则底部++;
32             if(st > ed) continue;  //当前队列为空了,直接返回
33             if(f[p-1] != -1) //如果当前p位,有数;
34                 f[i] = f[p-1] + num[q[st]];
35             for(j = st + 1; j <= ed; ++j) {
36                 if(f[q[j]-1] != -1)
37                     f[i] = min(f[i], f[q[j-1]] + num[q[j]]);
38             }
39         }
40         printf("%I64d\n",f[n]);
41     }
42     return 0;
43 }
时间: 2024-10-21 18:42:04

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

$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 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.cs

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 3709 K-Anonymous Sequence (单调队列优化)

题意:给定一个不下降数列,一个K,将数列分成若干段,每段的数字个数不小于K,每段的代价是这段内每个数字减去这段中最小数字之和.求一种分法使得总代价最小? 思路:F[i]表示到i的最小代价.f[i]=min(f[j]+sum[i]-sum[j]-(i-j)*a[j+1]);(i-j>=K) 对于j1,j2,j1<j2且j2更优得 f[j1]+sum[i]-sum[j1]-(i-j1)*a[j1+1]>f[j2]+sum[i]-sum[j2]-(i-j2)*a[j2+1] 得到: f[j1]

每日一dp(1)——Largest Rectangle in a Histogram(poj 2559)使用单调队列优化

Largest Rectangle in a Histogram 题目大意: 有数个宽为1,长不定的连续方格,求构成的矩形中最大面积 /************************************************************************/ /* 思路1. 当前为n的面积如何与n-1相联系,dp[i][j]=max(dp[i-1][k]) , 0<k<=j 描述:i为方块个数,j为高度 但是此题目的数据对于高度太变态,h,1000000000 ,n,1

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】2373 Dividing the Path(单调队列优化dp)

题目 传送门:QWQ 分析 听说是水题,但还是没想出来. $ dp[i] $为$ [1,i] $的需要的喷头数量. 那么$ dp[i]=min(dp[j])+1 $其中$ j<i $ 这是个$ O(n^2)$的东西,用单调队列优化一下就行了 复杂度$ O(L) $ 代码 #include <bits/stdc++.h> using namespace std; const int maxn=250; int A[maxn][maxn], num[maxn*maxn], id[100000

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-