单调队列与DP
Posted zzh-brim
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调队列与DP相关的知识,希望对你有一定的参考价值。
算是一个总结吧!
先来一个模板;
TYVJ 1305 最大子序和
题目描述
输入一个长度为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
输出样例#1:
7
数据范围:
100%满足n,m<=300000
这个可以算是单调队列优化dp的模板题了吧;
令f[i]表示以i为结尾的连续子序的最大值;
所以, f[i] = min (sum[i] - sum[j]) ( i - m <= j <= i); sum 为前缀和;
即 f[i] = sum[i] - min(sum[j])( i - m <= j <= i);
显然可以用单调队列维护前缀最小值;
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; int n, m; int a[300010]; int sum[300010]; deque <int> q; int ans; int main() { cin >> n >> m; for(register int i = 1 ; i <= n ; i ++) { scanf("%d", &a[i]); sum[i] = sum[i-1] + a[i]; } for(register int i = 1 ; i <= n ; i ++) { while(!q.empty() && sum[q.front()] > sum[i]) q.pop_front(); q.push_front(i); while(!q.empty() && i - m > q.back()) q.pop_back(); if(i != 1) { ans = max(ans, sum[i] - sum[q.back()]); } else ans = max(ans, sum[i]); } cout << ans << endl; return 0; }
以上是关于单调队列与DP的主要内容,如果未能解决你的问题,请参考以下文章
POJ2373 Dividing the Path(单调队列优化dp)