题面:
CodeForces - 1077F2:Pictures with Kittens
题意:
给定N个数,从中选出X个数,使得X个数的和最大,同时满足原数组中每连续的K个数都有一个数被选中
分析:
考虑dp[i][j] 表示前i个数中选了j个数且最后一个选的是第i个数的最大和,转移也很简单:dp[i][j] = max(dp[x][j-1])+a[i](i > x >= i-k)
暴力转移O(n^3)是过不了的,用单调队列维护【i,i-k】的单调性,每次直接O(1)转移
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 5e3+530;
LL dp[maxn][maxn],n,k,x,a[maxn];
deque<int> q;
int main(){
cin >> n >> k >> x;
memset(dp,-0x3f,sizeof(dp));
dp[0][0] = 0;
for(int i = 1;i <= n; ++i) cin >> a[i];
for(int i = 1;i <= x; ++i){
q.clear(); q.push_back(0);
for(int j = 1;j <= n; ++j){
while(!q.empty() && q.front()<j-k) q.pop_front();
dp[j][i] = dp[q.front()][i-1] + a[j];
while(!q.empty()&&dp[q.back()][i-1]<dp[j][i-1]) q.pop_back();
q.push_back(j);
}
}
LL ans = -1;
for(int i = n-k+1;i <= n; ++i) ans = max(ans,dp[i][x]);
cout << ans << '\n';
return 0;
}