小美定义一个数组a的权值计算如下:
首先将a的每一对相邻两项求和,得到一个b数组。那么b数组的最大值减最小值即为a数组的权值。
例如,若a*=[2,1,3],那么b=[3,4],b数组的极差是1。因此a*数组的权值为1。
现在小美希望你能构造一个长度为n的排列,满足权值尽可能小。你能帮帮她吗?
排列是指一个长度为n的数组,其中 1 到n每个元素恰好出现一次。
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
输入描述:
一个正整数,代表排列的长度。
2 ≤ n ≤ 200000
输出描述:
一个合法的排列。如果有多解输出任意即可。
示例1
输入例子:
3
输出例子:
2 1 3
例子说明:
这个数组的权值为 1。输出[2,3,1]等排列也是合法的。
思路:
-
排列组合求权值,n=3时有123、132、213、231、312、321共3!种排列法,其中要求权值最小为1的。
-
此时看列表123:1+2=3,2+3=5;
再看列表213:2+1=3,1+3=4;此时还看不出什么,于是构造长度为4的列表;
-
list[1, 2, 3, 4]:只需满足最大-最小=极小,则(4+1)-(3+1)=1,原序列变为list[2, 3, 1, 4]。再构造一个len5列表观察一下;
-
list[1, 2, 3, 4, 5]:变为list[2, 3, 4, 1, 5],发现权值为2,是否还存在更小权值呢?构造list[2, 3, 1, 4, 5]权值为5;
-
list[1, 2, 3, 4, 5, 6] -> weight = 10
list[2, 3, 4, 5, 1, 6] -> weight = 3
list[2, 3, 4, 1, 5, 6] -> weight = 6
-
在此猜测,只要挪动1的位置,就可以使最小值极大,最大值极小,以此求出极小值。
-
以n=5的列表举例:
若list_a[1, 2, 3, 4, 5] -> list_b1[3, 5, 7, 9] -> 9 - 3 = 6
交换list_a[i], list_a[i+1] = list_a[i+1], list_a[i]
若list_a[2, 1, 3, 4, 5] -> list_b2[3, 4, 7, 9] -> 9 - 3 = 6
……(此时运行第一个程序发现题解错误)
# 改变1的位置 def change_loc(_list): _list.pop(0) _list.insert(-1,1) return _list # 输入长度 n = int(input()) # 构建长度为n的列表a list_a = list(range(1,n+1)) # 调用 new_list_a = change_loc(list_a) for i in range(len(new_list_a)): print(new_list_a[i],end=" ")
预期输出
1 37 2 36 3 35 4 34 5 33 6 32 7 31 8 30 9 29 10 28 11 27 12 26 13 25 14 24 15 23 16 22 17 21 18 20 19
实际输出
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 1 37
若list_a[1, 5, 2, 4, 3] -> list_b2[6, 7, 6, 7] -> 7 - 6 = 1
我靠,还能这么搞
此时犹如醍醐灌顶,茅塞顿开,但仔细一想暴力枚举出weight肯定是不行的,一共有n!种排列方式肯定会超时间,那么看实际输出:
此时只要保持 (a[ i ] + a[ i + 1 ]) - (a[ i + 1 ] + a[ i + 2 ]) = 1 就可以了
实际上也可以输出
19 18 20 17 21 16 22 15 23 14 24 13 25 12 26 11 27 10 28 9 29 8 30 7 31 6 32 5 33 4 34 3 35 2 36 1 37
那么就可以根据结果来设计思路:
-
二分列表到位置n/2,获取list_a_1和list_a_2
n = 5 list_a = [1, 2, 3, 4, 5] list_a_1 = list_a[:int(n/2)] # 列表取一半位置 list_a_2 = list(set(list_a)-set(list_a_1)) # 取列表补集 out: [1, 2] [3, 4, 5]
-
倒序list_a_2
-
将list_a_2依次插入list_a_1(或者反过来插)
list_3 = [] for i in range(max(len(list_a_1),len(list_a_2_reverse))): if len(list_a_1) - 1 >= i: list_3.append(list_a_1[i]) if len(list_a_2_reverse) - 1 >= i: list_3.append(list_a_2_reverse[i]) return list_3
-
题解
def resetlist(_list):
list_a_1 = _list[:int(n / 2)]
list_a_2 = list(set(_list) - set(list_a_1))
list_a_2_reverse = list(reversed(list_a_2))
list_3 = []
for i in range(max(len(list_a_1),len(list_a_2_reverse))):
if len(list_a_1) - 1 >= i:
list_3.append(list_a_1[i])
if len(list_a_2_reverse) - 1 >= i:
list_3.append(list_a_2_reverse[i])
return list_3
# 输入长度
n = int(input())
# 构建长度为n的列表a
list_a = list(range(1,n+1))
# 调用
_list = resetlist(list_a)
for i in _list:
print(i, end=' ')
26/30 组用例通过
运行时间654ms
占用内存17636KB
为什么有4组用例不能通过啊,求高人指点