题意
有
个非负整数,选若干个数保证连续的数不超过
个,求选的数总和最大是多少。
思路
为了方便考虑问题,我们把题干转化为选若干个数,且间隔的数不超过
个,求选的数总和最小是多少。
设
为最后一个选的数为
时的最小总和,按照题设不难列出方程:
考虑用单调队列优化,不难发现,只要在枚举
时,实时维护
到
的最小值即可,这可以用单调队列实现。
代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 100003
typedef long long LL;
using namespace std;
LL E[N],dp[N];
bool cmp1(LL x,LL y){return x<y;}
template<LL *a,bool cmp(LL,LL)>struct monoque
{ //单调队列模板,对于a数组的,队头到队尾单调性为cmp的单调队列,队头是L
int q[N],L,R;
monoque(){L=1,R=0;}
void clear(){L=1,R=0;}
void del(int _){while(L<=R&&!cmp(a[q[R]],a[_]))R--;}
void push(int _){q[++R]=_;}
int front(){return q[L];}
int rear(){return q[R];}
void pop(int _){if(_>=q[L])L++;}
};
monoque<dp,cmp1>mq;
int main()
{
int n,k;
while(~scanf("%d%d",&n,&k))
{
LL sum=0,ans=1e18;
FOR(i,1,n)
{
scanf("%d",&E[i]);
sum+=E[i];
}
E[n+1]=0;
dp[0]=0;
mq.clear();
mq.push(0);
FOR(i,1,n+1)
{
dp[i]=dp[mq.front()]+E[i];
mq.del(i);
mq.push(i);
mq.pop(i-k-1);
}
printf("%lld\n",sum-dp[n+1]);
}
return 0;
}