思路
思路1
- 长度为m+1的序列必须不选择1个的最大值
- 反过来想,长度为m+1的序列中至少选择一个,选出来最小值,然后总和处理
- f[i] :前i个序列最后一个序列选的最小值
- 转移:在i前面的m+1个f[i] 中选择最小的 + a[i]
- 长度为m+1中f[i] 的最小值,单调队列优话
思路2
-
定义状态f[i] :前i个序列中合法的序列最大值
-
第i个数选、不选
-
不选:f[i-1]
-
选
-
选上这个点+之前的连续选点长度为1<=x<=m
-
转移:f[i-x-1] + a[i-x+1] +a[i-x+3] ±-- a[i];(i-x那个点不选,中间忽略掉)
-
用前缀和处理一下
-
max(f[i-x-1] + sum[i] - sum[i-x]) (1 <= x<=m)
-
x是i的前几个变量,这些变量的最大值,用单调队列优化,把sum[i] 提出来
-
max(f[i-x-1] + sum[i-x]) +sum[i]:前m个
-
把那个方程处理一下,处理成一个函数
ll g(int x) { if(!x ) return 0; return f[x-1] - sum[x]; }
-
-
#include<iostream>
#include<map>
#include<cmath>
#include<string.h>
using namespace std;
typedef long long ll;
const int N=1e6+100;
ll a[N],s[N];
int n,m;
ll sum[N];
// f[i] 前 i 个序列,最后一个序列选的最小值
// 长度m最小选择1个 min()
ll f[N];
ll q[N];
int hh=0,tt=0;
// max(f[i-x-1] + sum[i-x]) +sum[i];
ll g(int x)
{
if(!x ) return 0;
return f[x-1] - sum[x];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+ a[i];
}
for(int i=1;i<=n;i++)
{
if(i-q[hh]>m) hh++;
f[i] = max(f[i-1],sum[i] + g(q[hh]));
while(hh<=tt && g(q[tt]) <= g(i)) tt--;
q[++tt]=i;
}
cout<<f[n]<<endl;
return 0;
}