例题:最大子序和
题目大意:从长为
n
n
n的序列中找到长度不大于
m
m
m的连续子串,使其序列和最大。
解法:该题可使用单调队列优化
d
p
dp
dp求解,首先,求出序列的前缀和,然后维护一个长度不大于
m
m
m的双头队列,并且保持其是一个单调递增的队列,每次只需要以当前的前缀和与队头的前缀和相减就可以了,因为子序列和为前缀和
S
[
i
]
−
S
[
j
]
(
j
<
i
,
j
>
=
i
−
m
)
S[i] - S[j](j<i,j>=i-m)
S[i]−S[j](j<i,j>=i−m)因此,我们要保证
S
[
j
]
S[j]
S[j]越小越好,因此我们只要保留一个单调递增的序列就可以保持队头是符合要求的一个最小前缀和了。
代码实现(deque):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define x first
#define y second
const int N = 300010,M = 20;
const int mod = 1e9 + 7;
const double eps = 1e-6;
typedef pair<double,double>pdd;
int n,m;
deque<int>q;
ll s[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>s[i];
s[i] += s[i-1];
}
ll res = INT_MIN;
q.push_back(0);
for(int i=1;i<=n;++i){
if(i - q.front() > m) q.pop_front(); //单调队列
res = max(res,s[i] - s[q.front()]);
while(!q.empty() && s[q.back()] >= s[i]) q.pop_back();
q.push_back(i);
}
cout<<res<<endl;
return 0;
}