水题:给定n个数,要求任意k个数的和都为负数,对于每个数的操作不能减到小于初始的最小值,更改的代价为减小的值的和,问最小代价。
贪心
从左到右对于每段序列,考虑从右往左进行改变,因为这样对于后面的增益是最大的,然后减到最小值再往前找不为最小值的数再进行减操作。我用了链表优化
#include <stdio.h>
#include <stdlib.h>
const int maxn = 300000;
int a[maxn], pre[maxn], n, m;
int main() {
scanf("%d%d", &n, &m);
int minn = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] < minn) minn = a[i];
pre[i] = i-1;
}
int sum = 0, ans = 0;
a[0] = 0;
for (int i = 1; i < m; i++) sum += a[i];
for (int i = m; i <= n; i++) {
sum = sum+a[i]-a[i-m];
if (sum >= 0) {
for (int pos = i; pos >= 1; pos = pre[pos]) {
if (sum-(a[pos]-minn) < 0) {
int tar = a[pos]-1-sum;
ans += a[pos]-tar;
a[pos] = tar;
sum = -1;
pre[i+1] = pos;
break;
} else {
ans += a[pos]-minn;
sum = sum-a[pos]+minn;
a[pos] = minn;
}
}
}
}
printf("%d\n", ans);
for (int i = 1; i < n; i++) printf("%d ", a[i]);
printf("%d\n", a[n]);
}