單調隊列與DP
阿新 • • 發佈:2018-04-26
can show 滿足 emp push OS 輸出格式 while onclick
例如 1,-3,5,1,-2,3
當m=4時,S=5+1-2+3=7
當m=2或m=3時,S=5+1=6
一個數,數出他們的最大子序和
算是一個總結吧!
先來一個模板;
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> #includezZhBr<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