题目:

给定一个长度为 N 的数列 A1,A2,⋯,AN 。现在小蓝想通过若干次操作将 这个数列中每个数字清零。

每次操作小蓝可以选择以下两种之一:

选择一个大于 0 的整数, 将它减去 1 ;
选择连续 K 个大于 0 的整数, 将它们各减去 1 。
小蓝最少经过几次操作可以将整个数列清零?

输入格式
输入第一行包含两个整数 N 和 K 。

第二行包含 N 个整数 A1,A2,⋯,AN 。

输出格式
输出一个整数表示答案。

样例输入

4 2
1 2 3 4

样例输出

6

评测用例规模与约定
对于 20 %20% 的评测用例,1≤K≤N≤10 。

对于 40 %40% 的评测用例, 1≤K≤N≤100 。

对于 50 %50% 的评测用例, 1≤K≤N≤1000 。

对于 60 %60% 的评测用例, 1≤K≤N≤10000 。

对于 70 %70% 的评测用例, 1≤K≤N≤100000 。

对于所有评测用例, 1≤K≤N≤1000000,0≤Ai≤1000000 。

运行限制
最大运行时间:15s
最大运行内存: 512M

代码:

import java.util.Scanner;

import java.util.Arrays;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
static long count = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int k = scanner.nextInt();

long [] A = new long[n];
for (int i =0 ; i < n;i++){
A[i] = scanner.nextLong();
}
f(A,k);
for (int i=0;i<n;i++){
count+=A[i];
} //循环后都是不连续的数字只能一个个减
System.out.println(count);
}

public static void f(long[] A, int k){
int m =0;
while (m <= A.length-k){ //从第一个数字开始将k个连续数字减去其中最小值,依次向后进行。
long min =Integer.MAX_VALUE;
int index = -1;
for (int i =m ;i<m+k ;i++ ){
if (A[i]<=min){
min =A[i];
index = i;
}
}
for (int i =m ;i<m+k ;i++ ){
A[i] -= min;
}
count+=min; //最小数字则为对连续k个数字的操作次数。
m =index+1; //向后移动,移动到0的下一位

}




}
}

思路:

以题目中给的例子为例

4 2

1 2 3 4

首先找到前k个连续的数字减去最小值。

这里就是将1 2都减去1则这个数列变为了

0 1 3 4

在这里操作次数为1

接着向0后一位移动在这里就移到了1的位置。

重复上述步骤数列变为了

0 0 2 4

在这里操作次数为1

接着移到2

重复上述步骤数列变为

0 0 0 2

这里操作次数为2

已经没有连续k个不为零的数字了退出循环

还剩了一个单独的数字2将其减去

这里操作次数为2

总操作次数为1+1+2+2=6

注:本题一定不能将数列排序后再求解,我一开始的思路是将数列排序从后往前减将可以连续减k个数的规则最大限度的利用然后找出最小次数,结果就是过不去,经检查程序也没问题。最后通过看题解和再读题发现本题题意中其实是禁止排序的就是要在原数列上进行操作(一定要仔细读题)。