📅  最后修改于: 2023-12-03 14:56:44.058000             🧑  作者: Mango
本算法测验题目来自于ATcoder竞赛网站,题目中文名为“排列问题”。本文将会对该题进行详细介绍,并提供代码实现。
给定一个长度为 $n$ 的整数序列 $a$,找到一个排列 $p=(p_1,p_2,…,p_n)$,最大化以下表达式的值:
$$\sum_{i=1}^{n-1} |p_{i+1}-p_i|$$
其中 $|x|$ 表示 $x$ 的绝对值。
第一行包含整数 $n$。
第二行包含 $n$ 个整数 $a_1,a_2,…,a_n$。
输出最大化上述表达式的最大值。
$1≤n≤2⋅10^5,|a_i|≤10^9$
观察题目可得:
当 $n=1$ 时,答案为 $0$。
当 $n=2$ 时,答案为 $|a_2-a_1|$。
当 $n>2$ 时,将 $p$ 的序列按奇偶性分为两部分,即 $p=(p_1,p_3,…,p_{n-1})(p_2,p_4,…,p_n)$。对于两个数 $x_1$ 和 $x_2$,显然当 $x_1<x_2$ 时,$|x_1-x_2|=x_2-x_1$。假设现在有两个相邻的奇数位 $i,j(i<j)$ 和两个相邻的偶数位 $k,l(k<l)$,由于在 $p$ 中,$i,j,k,l$ 是奇偶交替排列的,因此有:
$$|p_i-p_j|+|p_k-p_l|=p_j-p_i+p_l-p_k$$
又因为 $p$ 满足 $p_1≤p_3≤…≤p_{n-1}$ 和 $p_2≤p_4≤…≤p_n$,因此将 $p$ 表示为如下形式:
$$p=(a_1,a_2,…,a_k,b_l,b_{l-1},…,b_1)$$
其中 $a_1≤a_2≤…≤a_k≤b_1≤b_2≤…≤b_l$,我们将 $b$ 逆序,得到 $b′=(b_l,…,b_2,b_1)$。则可以得到以下表达式:
$$\sum_{i=1}^{n-1} |p_{i+1}-p_i|=a_k-b_1+\sum_{i=1}^{l-1}(b′i-b{i+1})$$
将 $b$ 逆序操作看做按照 $b$ 非逆序的方式往前推进,每次只进行 $b_i$ 和 $b_{i+1}$ 的交换,称为“泡泡排序”,用此方式可以得到时间复杂度为 $O(n^2)$ 的算法。
如果我们将此问题转化为一个排序问题,并且将排序思路从“泡泡排序”改为快排,那么我们可以得到时间复杂度为 $O(n\log n)$ 的算法。
def quick_sort(arr, left, right):
if left >= right:
return
pivot = arr[(left+right)//2] # 选择pivot
i, j = left, right
while i <= j:
while i <= j and arr[i] < pivot: # 左指针右移
i += 1
while i <= j and arr[j] > pivot: # 右指针左移
j -= 1
if i <= j: # 交换
arr[i], arr[j] = arr[j], arr[i]
i += 1
j -= 1
quick_sort(arr, left, j)
quick_sort(arr, i, right)
if __name__ == '__main__':
n = int(input())
a = list(map(int, input().split()))
quick_sort(a, 0, n-1)
res = 0
for i in range(n//2):
res += a[n-i-1] - a[i]
print(res)
代码中,我们首先使用快速排序对序列 $a$ 进行排序,排序之后按照优化后的表达式计算答案即可,时间复杂度为 $O(n\log n)$。