成魔之路−> 算法提高课题解
思路:
-
1.状态表示
集合:以 i 为右端点,长度不超过 m 的连续子区间
属性:max -
2. 状态转移
f_i=\max\{s_i-s_j\}\ (i-m\le j\le i-1)
即,对于每一个\ s_i,找到一个\min\{s_j\}\ (i-m\le j\le i-1),可用单调队列来维护
因此,f_i=s_i-\min\{s_j\}\ (i-m\le j\le i-1)
最后,res=\max\{f_i\}\ (1\le i\le n)
完整代码
#include<bits/stdc++.h>
using namespace std;
const int N = 300010, INF = 0x3f3f3f3f;
int n,m;
int q[N],s[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
s[i]+=s[i-1]; //前缀和
}
int res=-INF,hh=0,tt=0;
for(int i=1;i<=n;i++)
{
if(q[hh]<i-m) hh++; //队头出列
res=max(res,s[i]-s[q[hh]]); //更新最值
while(hh<=tt&&s[q[tt]]>=s[i]) tt--; //严格单调递增
q[++tt]=i; //赋下标
}
cout<<res<<endl;
return 0;
}