📅  最后修改于: 2023-12-03 15:12:30.783000             🧑  作者: Mango
给定一个整数数组 nums,你可以对它进行任意次数的重排,使得重排后的数组可以首尾相连,形成一个长度为 n 的环。你的目标是最大化所有 $0 \leq i < n$ 的 gcd(nums[i], nums[(i+1) % n]),即求出重排后数组能够得到的最大可能值。
一个显然的结论是,对于一个长度为 n 的环,任意两个相邻元素的 gcd 一定是这个环的周长 k 的因数。因此,对于数组 nums,我们可以枚举其对应的周长 k,然后在所有周长为 k 的情况中寻找最大的 gcd 值。
具体来说,对于给定的周长 k,我们可以将 nums 划分为 n/k 组,每组包含 k 个元素。如果某一组中存在 0,则该组贡献的 gcd 值为 0,否则该组贡献的 gcd 值为这 k 个元素的 gcd。这样,我们可以将重排后得到的数组的所有贡献值相加,得到该排列下的总贡献值。枚举所有周长 k,取最大的总贡献值即可。
对于每个 nums[i],我们可以使用线性筛法预处理出其所有因子,存储在一个数组 factors[i] 中。时间复杂度为 $O(n \log n)$。
def get_factors(num):
primes = []
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
primes.append(i)
while num % i == 0:
num //= i
if num > 1:
primes.append(num)
return primes
n = len(nums)
factors = [[] for _ in range(n)]
for i in range(n):
factors[i] = get_factors(nums[i])
我们可以使用一个列表 group_factors 存储当前组合的 k 个元素的因子集合。具体来说,在枚举周长 k 时,我们先找到 nums 中所有与当前元素 nums[i] 的 gcd 为 k 的元素,然后将其与 nums[i] 分为一组。对于每个组,我们可以将其 k 个元素的因子集合取一个并集,得到 group_factors。如果 group_factors 非空,则当前组对总贡献值的贡献为其 k 个元素的 gcd 以及 k 的乘积。具体实现如下:
max_gcd = 1
for k in range(1, n + 1):
if n % k != 0:
continue
for i in range(n):
group_factors = set([])
for j in range(i, i + n, k):
group_factors = group_factors.union(set(factors[j]))
if len(group_factors) > 0:
gcd_val = reduce(gcd, nums[i:i + k])
max_gcd = max(max_gcd, gcd_val * k)
return max_gcd
预处理因子的时间复杂度为 $O(n \log n)$,枚举周长的时间复杂度为 $O(n^2)$,因此总时间复杂度为 $O(n^2 \log n)$。在 n 不是很大时可以接受。
from functools import reduce
from math import gcd
def get_factors(num):
primes = []
for i in range(2, int(num ** 0.5) + 1):
if num % i == 0:
primes.append(i)
while num % i == 0:
num //= i
if num > 1:
primes.append(num)
return primes
def max_gcd(nums):
n = len(nums)
factors = [[] for _ in range(n)]
for i in range(n):
factors[i] = get_factors(nums[i])
max_gcd = 1
for k in range(1, n + 1):
if n % k != 0:
continue
for i in range(n):
group_factors = set([])
for j in range(i, i + n, k):
group_factors = group_factors.union(set(factors[j]))
if len(group_factors) > 0:
gcd_val = reduce(gcd, nums[i:i + k])
max_gcd = max(max_gcd, gcd_val * k)
return max_gcd