题目 3179: 蓝桥杯2023年第十四届省赛真题-平均
题目描述
有一个长度为 n 的数组(n 是 10 的倍数),每个数 ai 都是区间 [0, 9] 中的整数。小明发现数组里每种数出现的次数不太平均,而更改第 i 个数的代价为bi,他想更改若干个数的值使得这 10 种数出现的次数相等(都等于n/10),请问代价和最少为多少。
解题思路分析
目的:
更改若干个数的值,使给出的数,出现的次数相等(都等于n/10),求更改的这些数需要的最少代价和。
思路:
求出相等的次数,既每个数应出现多少次 = n ➗ 10 ,我们记为平均出现次数
读入每个数
a
i
a_i
ai 和 它的代价
b
i
b_i
bi
统计每个数出现的次数,用数组counts保存起来
遍历数组counts,当找到一个数的 出现次数 > 平均出现次数 时,则表示要更改这个数
优先更改代价较低的数,并将更改的那个数的代价相加,循环次数 = 该数的出现次数 - 平均出现次数
代码实现
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 存放每个数字出现的次数
int[] counts = new int[n];
// 存放数字,和该数字对应的所有代价
Map<Integer, List<Integer>> map = new HashMap<>();
for (int i = 0; i < n; i++) {
// 读入数字和代价
int num = sc.nextInt();
int q = sc.nextInt();
if (!map.containsKey(num))
map.put(num, new ArrayList<>());
map.get(num).add(q);
counts[num]++;// 统计每个数字输入次数
}
// 输出的总代价
int total = 0;
// 每种数字应该出现的次数(平均出现次数)
int avg = n / 10;
for (int i = 0; i < n; i++) {
// 找出 出现次数 > 平均出现次数 的数
if (counts[i] > avg) {
// 找到该数字对应的代价列表
List<Integer> qs = map.get(i);
// 对代价进行排序
Collections.sort(qs);
// 取前面几个小的代价相加
for (int j = 0; counts[i] > avg; j++) {
total += qs.get(j);
counts[i]--;
}
}
}
System.out.println(total);
}