1. 程式人生 > >單調隊列與DP

單調隊列與DP

can show 滿足 emp push OS 輸出格式 while onclick

算是一個總結吧!

先來一個模板;

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; }
zZhBr

單調隊列與DP