题目描述
难度分:1300
输入T(≤104)表示T组数据。所有数据的n之和≤2×105。
每组数据输入n(1≤n≤2×105)和长为n的数组a(−109≤a[i]≤109)。保证所有a[i]互不相同。
首先,你需要往a中添加一个不同于任何a[i]的数。
然后选定一个正整数x。每次操作,可以把一个a[i]增加x。
注意每次操作中的x都是一样的。使所有a[i]都相同,至少要操作多少次?
输入样例
3
3
1 2 3
5
1 -19 17 -3 -15
1
10
输出样例
6
27
1
算法
数学
一开始以为是div3的题,提交的时候发现是EDU的题目,怪不得这么难。可以发现存在一个最优解,就是让所有的数都加某个x,直到所有数都加成maxi∈[1,n]ai。
那此时我们计算所有元素a[i]离这个目标值的距离maxi∈[1,n]ai−ai,这些距离的最大公约数就是x(这样可以使步长最大,让所有数变成目标值的步数最小),有了x就可以快速计算出原始数组a变得所有元素都相同最少需要操作多少次。接下来就可以考虑新加的这个数是多少,我们从maxi∈[1,n]ai开始,每次减x,第一个不在a中的数就是这个新加的an+1。
至于如何快速判断某个数在不在a中,只需要把a中元素存到一个哈希集合中就可以了。
复杂度分析
时间复杂度
对数组a排序的时间复杂度为O(nlog2n)。欧几里得算法求x需要对每个a[i]做一次gcd,时间复杂度为O(nlogA),其中A为a[i]的值域。最后确定an,从maxi∈[0,n)a[i]开始尝试,当尝试的数不在集合us中就可以马上确定出来,在最差情况下us中有O(n)级别的元素个数,每个都对尝试的数做了一次排除,这时候确定出an的时间复杂度为O(n)。
综上,整个算法的时间复杂度为O(n(log2n+logA)+n)。
空间复杂度
除去输入的数组a,哈希表的空间消耗为O(n),这也是整个算法的额外空间复杂度。
python代码
from math import gcd
t = int(input())
for _ in range(t):
n = int(input())
a = list(map(int, input().split()))
if n == 1:
print(1)
else:
a.sort()
us = set(a)
x = 0
for num in a:
x = gcd(x, a[-1] - num)
ans = 0
for num in a:
ans += (a[-1] - num) // x
k = 1
while a[-1] - k*x in us:
k += 1
an = a[-1] - k*x
ans += (a[-1] - an) // x
print(ans)