原题连接:http://www.51nod.com/Challenge/Problem.html#!#problemId=1483
有n种不同的化学试剂。第i种有ai升。每次实验都要把所有的化学试剂混在一起,但是这些试剂的量一定要相等。所以现在的首要任务是把这些化学试剂的量弄成相等。
有两种操作:
- 使其剂量翻倍
- 使其剂量减半(其实题目是对2取整)
问多少次操作后,可以将所有瓶中试剂含量相等。(1<n<10^5, 1<ai<10^5)
原本的解法在nod上验证以后,发现只通过了80%左右,发现还是考虑不周全
- 没考虑50,100这种倍数关系
- 没考虑98,99这种可以经过若干次/2以后变为相同的情况
- 以及其他没想到的情况
只在原来基础上考虑了情况1的时候:
num_2n = [2**n for n in range(17)]
count = 0
des = list()
n = int(input())
num = [int(i) for i in input().split()]
num.sort()
timesFlag = True
for i in range(1,n):
if num[i]%num[0]==0 and num[0] not in num_2n:
count += num[i]//num[0]-1
else:#一旦不全是倍数关系,则进行2^n求解过程
timesFlag = False
count = 0
break
if timesFlag==False:
for i in range(n):
while num[i] not in num_2n:
num[i] = num[i]//2
count += 1
des.append(num_2n.index(num[i]))
a = sum(des)//n
for i in des:
count += abs(a-i)
print(count)
提交后,发现还是只通过了19/20。头疼的是nod下载测试用例要什么币……
后来,受同学启发,还是采用暴力枚举法来解题,大概思想是:
- 把每个输入的数经过 乘2 或者 对2取整 的操作能达到的值全都记录下来,并且记录到该值需要的操作步骤。
- 然后找出【所有输入的数【都能达到的值】】
- 在其中(都能到达的值)找出操作数之和最小的值,其操作数即为正解。
代码如下:
n = int(input())
numList = [int(i) for i in input().split()]
cnt = [0]*(10**5+1)
arrive = [0]*(10**5+1)
rch = []
for num in numList:
tmp = num
opd = 0 # 操作数
while tmp <= 10**5: # 先乘
cnt[tmp] += opd
arrive[tmp] += 1
tmp *= 2
opd += 1
opd = 0
tmp = num
while tmp != 0:
if tmp%2 != 0 and tmp != 1: # 奇数
tmp //= 2
opd += 1
cnt[tmp] += opd
arrive[tmp] += 1
# 奇数对2取整,在*2会产生新值。
ttmp = tmp
topd = opd
ttmp *= 2
topd += 1
while(ttmp <= 10**5):
cnt[ttmp] += topd
arrive[ttmp] += 1
ttmp *= 2
topd += 1
else:
tmp //= 2
opd += 1
cnt[tmp] += opd
arrive[tmp] += 1 # 标记num能够到达tmp
for i in range(1,10**5+1):
if arrive[i] == n:
rch.append(cnt[i])
print(min(rch))
代码提交到nod以后,有2例超时,这个时候python的短板就体现出来了……