AcWing第2次周赛——第二题(3627. 最大差值 )贪心策略

题目描述

给定一个长度为 n 的非负整数序列 a1,a2,,an

你可以对该序列进行最多 k次操作。

每次操作选择两个非 0

的元素 aiaj,然后选择一个整数 c0cai),使得 ai 减少 caj 增加 c

请问,在操作全部完成后,序列中的最大值和最小值之差是多少。

例如,如果初始序列为 [5,5,5,5]k=1,则一种最优方案是将 a2 减少 5,将 a4 增加 5,得到序列

[5,0,5,10],这样最大值和最小值之差为 10

再例如,如果序列中的所有元素都为 0,则无法进行任何操作,所以最大值和最小值之差也为 0

输入格式

第一行包含整数 T,表示共有 T组测试数据。每组数据第一行包含整数 nk

第二行包含 n个整数 a1,a2,,an

输出格式

每组数据输出一行,一个整数,表示可以得到的最大差值。

数据范围

对于前三个测试点,1n10
对于全部测试点,1T10001k<n2×1050ai109,每个输入的 T 组数据的 n 之和不超过 2×105

输入样例:

2
4 1
5 5 5 5
3 2
0 0 0

输出样例:

10
0
 

解题思路——贪心策略

所谓贪心,就是每次找个次大值,将次大值减去本身,加到最大值上,那么结果一定是最大差值,循环k次该操作,即可得到最终答案,最终的最大差值就是存放在nums[n - 1]中

注意:这里我们不需要每次操作之后再对nums进行排序,只需要通过一个index变量来维护次大值,因为每次操作过后,原来的次大值都会变成0,那么当前的次大值就是原来的第三大的值(这也是我之前为啥 tql 的原因,就是在这里做了优化,将排序提到外面来,只做一次排序即可)

 

AC代码

 1 import java.util.Scanner;
 2 import java.util.Arrays;
 3 
 4 public class Main{
 5     public static void main(String[] args) {
 6         Scanner input = new Scanner(System.in);
 7         int T = input.nextInt();
 8         while (T-- > 0) {
 9             int n = input.nextInt();
10             int k = input.nextInt();
11             long[] nums = new long[n];
12             boolean allZero = true;
13             for (int i = 0; i < n; i++) {
14                 nums[i] = input.nextInt();
15                 if (nums[i] != 0) {
16                     allZero = false;
17                 }
18             }
19             if (allZero) {
20                 System.out.println(0);
21                 continue;
22             }
23             
24             // 排序
25             Arrays.sort(nums);
26             int index = n - 2;
27             for (int i = 0; i < k; i++) {
28                 nums[n - 1] += nums[index];
29                 nums[index] = 0;
30                 index--;
31             }
32             // 最后最小的值一定有0,而且一定会有多个0,所以最大差值就为最大值本身
33             System.out.println(nums[n - 1]);
34         }
35     }
36 }

时间复杂度:O(1000 * nlogn)

空间复杂度:O(n)

 

AcWing原题链接

posted @ 2021-06-05 22:32  没有你哪有我  阅读(75)  评论(0编辑  收藏  举报