第十四届蓝桥杯大赛软件组省赛 Python大学A组 D题-平均

问题描述

有一个长度为n的数组(n是10的倍数),每个数ai都是区间[0,9]中的整数。小明发现数组里每种数出现的次数不太平均,而更改第i个数的代价为bi,他想更改若干个数的值使得这10个数出现的次数相等(都等于 \frac{n}{10}),请问代价和最少为多少。

输入格式

输入的第一行包含一个正整数n。

接下来的n行,第i行包含两个整数ai,bi,用一个空格分隔

输出格式

输出一行包含一个正整数表示答案。

样例输入

10

1 1

1 2

1 3

2 4

2 5

2 6

3 7

3 8

3 9

4 10

样例说明

只更改第1,2,4,5,7,8个数,需要花费代价1+2+4+5+7+8=27

评价用例规模与约定

对于20%的测评用例,n<=1000;

对于所有的测评用例,n<=10^{5},0<bi<=2*10^{5}

思路讲解

一共是有n个数,每个数在0-9之间,要求0-9每个数在数组里出现的次数相等,即要把数组变成\frac{n}{10}个0,\frac{n}{10}个1,\frac{n}{10}个2,\frac{n}{10}个3,\frac{n}{10}个4,\frac{n}{10}个5,\frac{n}{10}个6,\frac{n}{10}个7,\frac{n}{10}个8,\frac{n}{10}个9。

对于0-9之间的每个数,可以统计用一个数组他们在数组里面出现的次数,再用一个字典统计该数字在每个数ai的修改代价。具体初始化形式如下:

n = int(input())

s = dict()                           #定义一个字典,统计0-9每个数字的修改代价,字典的键是数字,值是一个列表,因为一个数字出现了多次会有多个代价

s2 = [0 for i in range(10)]  #定义一个数组,记录0-9每个数字出现的次数

for i in range(n):

  a,b = map(int,input().split())

  if a not in s:

    s[a] =[b]

  else:

    s[a].append(b)

  s2[a]+=1

遍历包含每个数字出现的次数的数组s2,s2[j]表示数字j出现的次数,j的值在0-9之间,此时分三种情况,一种是这个数字出现的次数<\frac{n}{10},一种是这个数字出现的次数=\frac{n}{10},一种是这个数字出现的次数>\frac{n}{10}

1.如果s2[j]<\frac{n}{10},则表示数字j出现的次数不满足要求,应该由别的数字变为数字j,即数组中为数字j的数不用发生改变。

2.如果s2[j]=\frac{n}{10},则表示数字j出现的次数已满足要求,数组中为数字j的数也不用发生改变。

3如果s2[j]>\frac{n}{10}, 则表示数字j出现的次数不满足要求,应该将数组中的部分等于数字j的元素改为其他元素,具体改变成什么数字不用管,因为修改成其他任意数字的代价都是一样的。

至此,只有第三种情况才需要对数组a进行修改,若k = s2[j]-\frac{n}{10},即只需要将数组里面的k个为j数修改成别的数字即可,因为之前存储过数组中值为数字j的每个数的代价,只需要在里面取最小的k个求和即可。

num=0

for i in range(10):

  if s2[i]>n//10:

    k = s2[i]-n//10

    s3 = sorted(s[i])

    num+=sum(s3[:k])

完整代码

最后附上完整代码

import os
import sys

# 请在此输入您的代码
n = int(input())
s = dict()
s2 = [0 for i in range(10)]
for i in range(n):
  a,b = map(int,input().split())
  if a not in s:
    s[a] =[b]
  else:
    s[a].append(b)
  s2[a]+=1
num=0
for i in range(10):
  if s2[i]>n//10:
    k = s2[i]-n//10
    s3 = sorted(s[i])
    num+=sum(s3[:k])
print(num)


官网原题地址

用户登录icon-default.png?t=N7T8https://www.lanqiao.cn/problems/3532/learning/?page=1&first_category_id=1&sort=students_count&second_category_id=3&name=%E5%B9%B3%E5%9D%87

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值