题意:给你一段序列,让你选出一些区间,然后使和最大但是区间长度不超过k。
一开始想设f[i][j]表示做到第i位,连续选了j个,这明显n^2,但是发现可以优化。j是可以通过单调队列直接算出来的。
然而空间会爆炸(滚动太麻烦)。
所以我们换一个方程式子f[i]=max(f[i],f[j]+sum[j~i])这样维护起来就方便很多了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=5e5+5;
typedef long long ll;
ll f[N],sum[N];
int n,k,a[N];
struct node
{
ll num,x;
}q[N];
int main()
{
scanf("%d%d",&n,&k);
fo(i,1,n)scanf("%d",&a[i]),sum[i]=sum[i-1]+1ll*a[i];
int t=1,w=0;
fo(i,0,n)
{
while (t<=w&&q[t].num<i-k-1)t++;
if (i<=k)f[i]=sum[i];
else f[i]=sum[i]+q[t].x;
if (i==n)break;
while (t<=w&&q[w].x<=f[i]-sum[i+1])w--;
q[++w].num=i;
q[w].x=f[i]-sum[i+1];
}
printf("%lld\n",f[n]);
return 0;
}