📜  算法测验|须藤放置[1.5] |问题2(1)

📅  最后修改于: 2023-12-03 14:56:44.058000             🧑  作者: Mango

算法测验-须藤放置(1.5)-问题2

本算法测验题目来自于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)$。