题目链接:http://codeforces.com/problemset/problem/1077/F2
题意:https://blog.csdn.net/nka_kun/article/details/84645060的增强版
思路:我们根据上一题发现,其实更新f[i][j]的过程就是在f[i-1][j-1]到f[i-k][j-1]之间找一个最大值,用这个值来
更新f[i][j].这里我们就想到了单调栈这一类的东西,我们可以用一个双端队列来解决这个问题.
双端队列是一个递减队列,每次从front压进一个新的元素来,我们都把比他小的pop掉,并且把底部过期的pop掉
每次取得时候就从底部取出一个即可.
代码:
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 2e5+5;
const double eps = 1e-12;
const int inf = 0x3f3f3f3f;
map<int,int>::iterator it;
int n,k,m;
ll a[5678];
ll f[5003][5003];
deque<pair<ll,int> > q[5005];
int main()
{
cin>>n>>k>>m;
for(int i = 1;i<= n;i++)
cin>>a[i];
for(int i = 0;i<= n;i++)
for(int j = 0;j<= n;j++)
f[i][j] = -1e15;
for(int i = 1;i<= n;i++)
{
if(i<= k)
f[i][1] = a[i];
for(int j = 2;j<= i;j++)
{
int v = j-1;
while(!q[v].empty()&&q[v].back().second< i-k) q[v].pop_back();
f[i][j] = max(f[i][j],q[v].back().first+a[i]);
}
for(int j = 1;j<= i;j++)
{
while(!q[j].empty()&&q[j].front().first<= f[i][j]) q[j].pop_front();
q[j].push_front(make_pair(f[i][j],i));
}
}
ll ans = -1e15;
for(int i = n;i>= n-k+1;i--)
ans = max(ans,f[i][m]);
if(ans< 1)
cout<<-1<<"\n";
else
cout<<ans<<endl;
return 0;
}