单调队列优化DP
2017-04-09 10:44
211 查看
单调队列优化DP:顾名思义,就是拿单调队列对DP进行优化。可以把N维的DP降低到N-1维。
先来看一道例题:
//---------------------------------------------------------------------------------------------------------------//
输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大。(n<=300000)
例如 1,-3,5,1,-2,3
当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6
//----------------------------------------------------------------------------------------------------------------//
对于这道题,很明显可以用DP来解决,DP方程为:
f[i] = sum[i] - max(sum[j] | i-M<=j<=i)
答案为max(f[i] | 1<=i<=n)。
这样做的话,时间复杂度为O(n^2),超时。
注意到max(sum[j]),这时求静态区间的最大值,可以用RMQ进行优化。
时间复杂度为O(nlogn)=O(300000 * 18)=O(5400000)。对于本题,还可以承受。
可如果n再大一点的话,O(nlogn)的时间是无法接受的。对此,就可以用单调队列来进行优化。
对于每一个i:
1,如果sum[队首]>sum[i],则删除队首。
2,插入i
3,若对尾不在范围内(对于本题,即对尾<i-m),删除对尾。
这样的话:就可以保证队列元素(即i)的单调性和队列优先级(即sum[i])的单调性,证明略。
如果上面还看不懂,那就看程序吧。
所以,每当遇到形如f[i] = max or min(a[k] | p[i]<=k<=q[i]) + b[i] (q[i],p[i]单调,b[i]与k无关)这样的DP方程的时候,就可以用如上方法进行单调队列优化。
先来看一道例题:
//---------------------------------------------------------------------------------------------------------------//
输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大。(n<=300000)
例如 1,-3,5,1,-2,3
当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6
//----------------------------------------------------------------------------------------------------------------//
对于这道题,很明显可以用DP来解决,DP方程为:
f[i] = sum[i] - max(sum[j] | i-M<=j<=i)
答案为max(f[i] | 1<=i<=n)。
这样做的话,时间复杂度为O(n^2),超时。
注意到max(sum[j]),这时求静态区间的最大值,可以用RMQ进行优化。
时间复杂度为O(nlogn)=O(300000 * 18)=O(5400000)。对于本题,还可以承受。
可如果n再大一点的话,O(nlogn)的时间是无法接受的。对此,就可以用单调队列来进行优化。
对于每一个i:
1,如果sum[队首]>sum[i],则删除队首。
2,插入i
3,若对尾不在范围内(对于本题,即对尾<i-m),删除对尾。
这样的话:就可以保证队列元素(即i)的单调性和队列优先级(即sum[i])的单调性,证明略。
如果上面还看不懂,那就看程序吧。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <cstdlib> #include <stack> #include <queue> #include <map> #include <list> #include <set> using namespace std; typedef long long LL; #define Maxn 300010 int n,m; list<int> h; LL sum[Maxn]; LL ans; int main() { scanf("%d%d",&n,&m); int x; for(int i=1;i<=n;i++) { scanf("%d",&x); sum[i] = sum[i-1] + (LL)x; } ans = max(0LL,sum[1]);//全部是负数的情况 h.push_front(1); for(int i=1;i<=n;i++) { for(;( !h.empty() ) && sum[h.front()] > sum[i]; h.pop_front() );//1 h.push_front(i);//2 for(;( !h.empty() ) && i-m > h.back(); h.pop_back() );//3 ans = max(ans,sum[i] - sum[h.back()]);//计算答案 } printf("%I64d\n",ans); return 0; }
所以,每当遇到形如f[i] = max or min(a[k] | p[i]<=k<=q[i]) + b[i] (q[i],p[i]单调,b[i]与k无关)这样的DP方程的时候,就可以用如上方法进行单调队列优化。
相关文章推荐
- [SCOI2010] 股票交易 (单调队列优化dp)
- 用单调队列的思想优化一些dp问题
- 【bzoj1499】[NOI2005]瑰丽华尔兹 【单调队列优化dp】
- 1023: [SHOI2008]cactus仙人掌图(DP+单调队列优化)
- 【BZOJ 1233】 [Usaco2009Open]干草堆tower (单调队列优化DP)
- [BZOJ2806][Ctsc2012]Cheat(后缀自动机+单调队列优化dp)
- hdu 3401 单调队列优化DP
- 【hdu 5945 】 【dp+单调队列优化】Fxx and game【求数x最少经过多少次变换能变为1,(1)如果x%k==0,那么可以x=x/k。(2)x=x-i,(1<=i<=t)】
- hdu 1171 Dividing 单调队列优化dp
- uestc599最小花费【单调队列优化dp】
- HDU 5945 Fxx and game 单调队列优化DP
- bzoj1044[HAOI2008]木棍分割 单调队列优化dp
- bzoj 2216: Lightning Conductor 单调队列优化dp
- hdu 4374 One hundred layer 单调队列优化dp
- NKOJ 2151【单调队列】烽火传递 单调队列优化DP
- bzoj1499(这道题改天重做,dp+单调队列优化)
- HDU 3401 单调队列优化DP
- lightoj-1415:Save the Trees (单调队列优化dp)
- 浅谈单调队列优化dp
- HDU 3401 Trade 单调队列优化DP