321
社区成员




给定一组n个正整数,要求每次选其中一个数乘以或除以一个素数(称为一次凑数),问至少需要凑数多少次可以把所有的数都凑成相等。
可以把所有的数都凑成相等需要至少进行的凑数次数t(t>=0)。
周赛57期的新题目,当时没能 ac ,然后,今天随便弄了弄,居然 ac 了,但不明白为什么 ac 的,呵呵
arr = list(map(int,input().split()))
n,m = len(arr),int(max(arr) ** .5 + 1)
ans = 0
for i in range(2,m):
z = []
for j in range(n):
c = 0
while arr[j] % i == 0:
c += 1
arr[j] //= i
z.append(c)
ans += sum(z) - min(z) * n
print(ans + n - arr.count(1))
其中有个测试用例是 [934906, 869814, 593826, 642589, 904024, 572674, 718422, 812732, 873256, 582947]
能AC的答案是38次,也就是所有数字都向下除,全变成1。
但我的代码得到的是32次,即全变成2(其中奇数除到1后再乘以2)
由此可见,C站的“标准答案”似乎只考虑了除法,并没有考虑乘法可能更优。
此题是好题,但从结果来看,题意描述有很大的问题,如果“凑数”表示可乘也可除,那么最短“距离”应该是每个素数个数到其中位数的距离之和。但从结果来看,能AC的代码却是到每个素数个数最少的个数距离之和,显然并不是最优的。
我实现的代码如下,只要将循环改写成注释部分就能AC了,但我并不相信C站,所以我还是坚持自己,除非有人能说服我 :D
from collections import defaultdict
def fun(n):
cnt = 0
if n % 2 == 0:
while n % 2 == 0:
cnt += 1
n //= 2
factors[2].append(cnt)
for i in range(3, int(n**0.5)+1, 2):
if n % i == 0:
cnt = 0
while n % i == 0:
cnt += 1
n //= i
factors[i].append(cnt)
if n > 2: factors[n].append(1)
factors = defaultdict(list)
for n in arr: fun(n)
m = len(arr)//2 + 1
res = 0
for f in factors.values():
f.sort()
p = len(f) - m
if p >= 0:
res += sum(abs(f[p]-i) for i in f) + (len(arr)-len(f))*f[p]
else:
res += sum(f)
# if len(f) == len(arr):
# res += sum(f) - min(f)*len(arr)
# else:
# res += sum(f)
print(res)