题意:

  给定含有n个元素的数列a,要求将其划分为若干个连续子序列,使得每个序列的元素之和小于等于m,问最小化所有序列中的最大元素之和为多少?(n<=105。例:n=8, m=17,8个数分别为2 2 2 | 8 1 8 |1 2,答案为12。)

思路:

  想明白一个队列+一个set就能完美解决这个问题?

  首先DP的转移式子是:dp[i]=min( dp[j] +max[j+1, i]  ),且sum[i]-sum[j]<=m,j为枚举的断开处。暴力寻找一个合适的j的复杂度为O(n2)。那么问题就在于如何寻找这个合适的j。

  先假设j的范围是(low, i],而max是随着j的增大单调不减的,则max[k,i]>=max[p,i]且k<p是肯定的。那么如果出现max[k,i]=max[p,i]且k<p的话,j=k明显更佳,因为dp[k]<=dp[p]是肯定的!那么如果出现max[k,i]>max[p,i]且k<p的话,取哪个就难说了,也是因为dp[k]<=dp[p] 。

  根据转移式子知道,j肯定是不跟i同组的,这是根据dp[j]的定义来决定的。那么j有可能的取值为low,或者为k(a[k]>a[i]),那么单调队列就形成了,队列中保存下标,表示所有a[k]>a[i]且low<=k<=i。

  但是这队列有什么用?值val可能等于队列中任一元素u,而val=dp[u]+max[u+1,i]是没有什么规律的。直接将所有val装进set中,最小的set.begin()就是我们要找的答案了。如果维护单调队列时需要删除怎么办?直接将算出来的val在set中删除。

  注意:如果队列为空,即a[i]是a[low,i]中的最大值,那么最多只能取j=low。如果low一旦改变了,队头元素也有可能改变喔~因为队头算出来的val可能是根据更小的low算出来的。由于多个val相同的情况是存在的,所以用multiset。

  1. //#include <bits/stdc++.h>
  2. #include <iostream>
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <set>
  7. #include <deque>
  8. #include <map>
  9. #include <algorithm>
  10. #include <vector>
  11. #include <iostream>
  12. #define pii pair<int,int>
  13. #define back que[rear-1]
  14. #define INF 0x7f7f7f7f
  15. #define LL long long
  16. #define ULL unsigned long long
  17. using namespace std;
  18. const double PI = acos(-1.0);
  19. const int N=;
  20. LL sum[N], has[N], dp[N];
  21. int a[N], que[N], top, rear, low;
  22. multiset<LL> sett;
  23. LL cal(int n,LL m)
  24. {
  25. for(int i=; i<=n; i++)
  26. {
  27. if(a[i]>m) return -;
  28. while( sum[i]-sum[low]>m ) low++;
  29.  
  30. //过期的只可能在top处
  31. while( top<rear && que[top]<=low )
  32. sett.erase( has[top++] );
  33.  
  34. if(top<rear)
  35. {
  36. //队头的val有可能会改变,因为下限low提高了
  37. sett.erase( has[top] );
  38. has[top]=dp[low]+a[ que[top] ];
  39. sett.insert( has[top] );
  40. }
  41. //插入队列先
  42. while(top<rear && a[i]>a[ que[rear-] ] )
  43. sett.erase( has[--rear] );
  44.  
  45. que[rear]=i; //只记下标
  46. LL val=;
  47. if(top^rear) val=dp[ que[rear-] ]+a[i];
  48. else val=dp[low]+a[i]; //top=rear时,a[i]就是最大的
  49. sett.insert( val );
  50. has[rear++]=val;
  51. dp[i]=*sett.begin(); //取最小
  52. }
  53. return dp[n];
  54. }
  55.  
  56. int main()
  57. {
  58. //freopen("input.txt","r",stdin);
  59. int n;LL m;
  60. scanf("%d%lld", &n, &m);
  61. for(int i=; i<=n; i++) //机器
  62. {
  63. scanf("%d",&a[i]);
  64. sum[i]=sum[i-]+a[i];
  65. }
  66. printf("%lld\n", cal(n,m));
  67. return ;
  68. }

AC代码

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

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

    Poj   AcWing Description 给定一个长度为N的序列 A,要求把该序列分成若干段,在满足“每段中所有数的和”不超过M的前提下,让“每段中所有数的最大值”之和最小. N<=10 ...

  2. poj3017 Cut the Sequence 单调队列 + 堆 dp

    描述 把一个正数列 $A$分成若干段, 每段之和 不超过 $M$, 并且使得每段数列的最大值的和最小, 求出这个最小值. 题目链接 题解 首先我们可以列出一个$O(n^2)$ 的转移方程 : $F_i ...

  3. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

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

    题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂 ...

  5. 单调队列优化DP——习题收集

    前言 感觉可以用单调队列优化dp的模型还是挺活的,开个随笔记录一些遇到的比较有代表性的模型,断续更新.主要做一个收集整理总结工作. 记录 0x01 POJ - 1821 Fence,比较适合入门的题, ...

  6. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

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

  8. hdu3401:单调队列优化dp

    第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...

  9. Parade(单调队列优化dp)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    ...

  10. BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP

    BZOJ_3831_[Poi2014]Little Bird_单调队列优化DP Description 有一排n棵树,第i棵树的高度是Di. MHY要从第一棵树到第n棵树去找他的妹子玩. 如果MHY在 ...

随机推荐

  1. 下载win7/win8/win10镜像

    关于给电脑换系统,很多人会花钱去电脑店里换,或者是下载Ghost系统.但这些系统都不是微软原版的,制作者已经集成了很多常用软件或垃圾软件进去.我在这给大家介绍的是如何下载正版的Windows系统.这个 ...

  2. UVaLive 3266 Tian Ji -- The Horse Racing (贪心)

    题意:田忌赛马,每胜一局就得200,负一局少200,问最多得多少钱. 析:贪心,如果最快的马比齐王的还快,就干掉它,如果最慢的马比齐王的马快,就干掉它,否则用最慢的马去和齐王最快的马比. 代码如下: ...

  3. Windows对象、句柄与MFC对象

    windowsmfc编程c 目录(?)[-] Windows对象句柄与MFC对象 windows对象 句柄 mfc对象 杂谈 Windows对象.句柄与MFC对象 (2009-04-28 22:11: ...

  4. JAVA基础--IO输入输出(File使用)17

    一. File中的方法 1.  列举方法 /* * 获取指定目录以及子目录下的所有文件和文件夹 */ public class ListFilesDemo { public static void m ...

  5. CMD运行指令

    CMD运行指令   开始→运行→CMD→键入以下命令即可:   gpedit.msc-----组策略 sndrec32-------录音机   Nslookup-------IP地址侦测器 explo ...

  6. SEO优化之——hreflang(多语言网站优化)

    用法格式 <link rel="alternate" href="URL" hreflang="zh-cn"> // href ...

  7. jQuery EasyUI/TopJUI创建日期时间输入框

    jQuery EasyUI/TopJUI创建日期时间输入框 日期时间输入框组件 HTML 和日期输入框类似,日期时间输入框允许用户选择日期和指定的时间并按照指定的输出格式显示.相比日期输入框,它在下拉 ...

  8. glassfish 自定义 jaas realm

    https://www.oschina.net/translate/custom-jaas-realm-for-glassfish-3

  9. Eclipse Photon 小技巧(tips)

    本文内容: Eclipse 4.8版本 代号 photon  光量子 ,感觉更像ide了,虽然这些技巧广为认知,但是作为eclipse来说,也是很重要的. Code completion allows ...

  10. Swing 100行画图示例

    关键内容,可以自行扩展 package main; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt ...