题目链接:http://codeforces.com/contest/940/problem/E
题意:给你一个长为n的序列和一个数字c,你要将这个序列切成若干段,对于每一段,这段中最小的[n/c]个数字(向下取整)都会被自动删除,问怎么切割使最后剩下的数字和最小
思路:考虑dp[i]表示前i个数字能删掉的最大和,那么有dp[i] = max(dp[i-1], dp[i-c]+min(a[k] i-c<k<=i))
最后答案就是sum(a[i])-dp[n],其中min(a[k] i-c<k<=i)直接用单调队列处理最方便
#include<stdio.h>
#include<algorithm>
using namespace std;
#define LL long long
LL dp[100005];
int a[100005], q[100005];
int main(void)
{
LL sum;
int n, m, i, back, top;
scanf("%d%d", &n, &m);
sum = 0;
for(i=1;i<=n;i++)
{
scanf("%d", &a[i]);
sum += a[i];
}
back = 1, top = 0;
for(i=1;i<=n;i++)
{
dp[i] = dp[i-1];
while(top>=back && q[back]<=i-m)
back++;
while(top>=back && a[q[top]]>=a[i])
top--;
q[++top] = i;
if(i>=m)
dp[i] = max(dp[i], dp[i-m]+a[q[back]]);
}
printf("%lld\n", sum-dp[n]);
return 0;
}