一、题目
题目描述
给一个数组,一共有 n n\ n 个数。
你能进行最多 k k\ k 次操作。每次操作可以进行以下步骤:
- 选择数组中的一个偶数 aia_iai,将其变成 ai/2a_i/2ai/2 。
现在你进行不超过 k k\ k 次操作后,让数组中所有数之和尽可能小。请输出这个最小的和。
输入描述:
第一行输入两个正整数 n n\ n 和 k k\ k ,用空格隔开
第二行输入n n\ n 个正整数 aia_iai
数据范围:
1≤n≤100000,1≤k≤1091 ≤ n≤100000,1≤k≤10^91≤n≤100000,1≤k≤109
1≤ai≤1091≤a_i≤10^91≤ai≤109
输出描述:
一个正整数,代表和的最小值。
示例1
输入
复制5 3 2 4 8 10 11
5 3
2 4 8 10 11
输出
复制24
24
说明
对8操作2次,对10操作1次,最后的数组是2 4 2 5 11。可以证明这样的操作是最优的。
二、思路解析
这道题有很多种解法,但核心思想是利用贪心,做出局部最优的选择,从而达到全局最优的结果。
在这个问题中,我是利用了大根堆这个数据结构,对数组中的 偶数 进行操作。
每次操作选择当前数组中的最大偶数,并将其减半,直到操作次数(k)用尽或者数组中没有偶数为止。
具体实现请看下面代码👇
三、完整代码
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.LinkedList;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
PriorityQueue<Integer> heap = new PriorityQueue<>(
(a, b) -> {
return b - a;
});
long sum = 0, x;
for(int i = 0; i < n; i++){
x = in.nextLong();
sum += x;
if(x % 2 ==0){
heap.add((int)x);
}
}
while(!heap.isEmpty() && k-- != 0){
long t = heap.poll() / 2;
sum -= t;
if(t % 2 == 0){
heap.add((int)t);
}
}
System.out.println(sum);
}
}
以上就是本篇博客的全部内容啦,如有不足之处,还请各位指出,期待能和各位一起进步!