题目描述
难度分:1200
输入T(≤500)表示T组数据。每组数据输入n(2≤n≤100)和长为n的数组a(1≤a[i]≤1017)。保证所有a[i]互不相同。
找到一个在[1,1018]中的k,使得所有a[i]=a[i]%k后,a中恰好有两个不同的数。
输出这个k。如果有多个答案,输出任意一个。可以证明,答案是存在的。
输入样例
5
4
8 15 22 30
5
60 90 98 120 308
6
328 769 541 986 215 734
5
1000 2000 7000 11000 16000
2
2 1
输出样例
7
30
3
5000
1000000000000000000
算法
枚举
先考虑一个简单情况,如果a数组既有奇数又有偶数,那么答案就是2。
否则分析性质,我们发现对一个数模上2b其实就是保留其二进制的最后b+1位。所以k=4开始,检查是否合法,合法就输出k,不合法就倍增k。由于a中所有元素都不相同,必然会存在一个k,使得保留的二进制后缀刚好是两个不同的数。
复杂度分析
时间复杂度
k的尝试次数就是a中最大值取log之后的级别,时间复杂度为O(log2max(a)。而每尝试一个k,就要遍历a数组检查一下是不是只有两个取模之后的结果,时间复杂度为O(n)。因此,整个算法的时间复杂度为O(nlog2max(a))。
空间复杂度
空间消耗在于每检查一个k是否合法时,需要一个集合来保存a[i]%k的结果。在最差情况下可能每个元素模k的结果都不相同,空间复杂度为O(n)。
python代码
t = int(input())
for _ in range(t):
n = int(input())
a = list(map(int, input().split()))
def check(k):
b = set()
for ai in a:
b.add(ai % k)
return len(b) == 2
cnt0, cnt1 = 0, 0
for ai in a:
if ai&1:
cnt1 += 1
else:
cnt0 += 1
if cnt0 > 0 and cnt1 > 0:
print(2)
else:
if n == 2:
print(max(a))
else:
k = 4
while 1:
if check(k):
print(k)
break
k <<= 1