tyvj1305 最大子序和 【单调队列优化dp】
生活随笔
收集整理的這篇文章主要介紹了
tyvj1305 最大子序和 【单调队列优化dp】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
描述
輸入一個長度為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
輸出
7備注
數據范圍:100%滿足n,m<=300000
題解
我們由題設f[i]為i位置最大子段和,得到狀態轉移方程f[i] = max(f[i - 1],sum[i] - sum[k]); ?【i - k <= m】 很明顯這樣做是O(n ^ 2) 對于求sum[i] - sum[k]的最大值,我們可以用單調隊列優化單調隊列 單調隊列,顧名思義,就是單調的隊列,用以O(1)求最值 單調隊列用雙向隊列維護,隊首是最值【假設是最大】 每次我們向隊尾插入一個元素時,我們若隊尾的元素比它要小就將他刪除,直至隊列為空或者隊尾元素大于插入 元素,再將其插入 例如5 3 1,我們要插入4 檢查1 < 4,隊列變為5 3 檢查3 < 4,隊列變為5 檢查5 > 4,隊列變為5 4 插入完成
你會發現這樣的操作能滿足隊列一定單調,而隊首就是我們要的值 但注意隨著時間的推移,隊首元素可能“過時”,就是超出了我們所規定的范圍,這個時候就刪除隊首,直至滿足范圍 由于每個元素最多進隊出隊一次,所以總復雜度O(n)
那么這題就好做了,我們用一個單調隊列維護前m個sum值,每次只用O(1)就可以轉移方程 復雜度O(n)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long int #define REP(i,n) for (int i = 1; i <= (n); i++) #define fo(i,x,y) for (int i = (x); i <= (y); i++) #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next) using namespace std; const int maxn = 300005,maxm = 100005,INF = 1000000000; inline int read(){int out = 0,flag = 1;char c = getchar();while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}return out * flag; } int n,m,q[maxn],head,tail,sum[maxn],f[maxn]; int main() {n = read(); m = read();REP(i,n) sum[i] = sum[i - 1] + read();head = tail = 0; q[head] = 0;for (int i = 1; i <= n; i++){while (i - q[head] > m) head++;f[i] = max(f[i - 1],sum[i] - sum[q[head]]);q[++tail] = i;while (tail > head && sum[q[tail]] < sum[q[tail - 1]]) q[tail - 1] = q[tail],tail--;}cout<<f[n]<<endl;return 0; }
轉載于:https://www.cnblogs.com/Mychael/p/8282827.html
總結
以上是生活随笔為你收集整理的tyvj1305 最大子序和 【单调队列优化dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java getClass() VS i
- 下一篇: php获取ios或android通过文件