原题题目
n个小朋友站成一排。
现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
每个小朋友都有一个不高兴的程度。
开始的时候,所有小朋友的不高兴程度都是 0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加 1,如果第二次要求他交换,则他的不高兴程度增加 2(即不高兴程度为 3),依次类推。当要求某个小朋友第 k次交换时,他的不高兴程度增加 k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
输入格式
输入的第一行包含一个整数 n,表示小朋友的个数。
第二行包含 n
个整数 H1,H2,…,Hn,分别表示每个小朋友的身高。
输出格式
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
数据范围
1≤n≤100000
,
0≤Hi≤1000000
输入样例:
3
3 2 1
输出样例:
9
样例解释
首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
思路
一开始看到这道题的思路是暴力枚举,先寻找之前有几个数比当前所在数大,再寻找之后有几个数比当前所在数小
下面是暴力解法()
n = int(input()) lst_child = list(map(int, input().split())) sum = [0 for _ in range(n)] result = [0 for _ in range(n)] ans = 0 for i in range(n): for j in range(0, i): count = 0 if lst_child[j] > lst_child[i]: # 之前有几个比它大的数 count += 1 sum[i] += count for i in range(n - 1, -1, -1): for j in range(n - 1, i - 1, -1): count = 0 if lst_child[j] < lst_child[i]: # 之后有几个比他小的数 count += 1 sum[i] += count # 计算sum中的结果 for i in range(n): result[i] = (1 + sum[i]) * sum[i] // 2 for i in range(n): ans += result[i] print(ans)
然后不出所料,TLE了,在蓝桥官网上只过了3个测试点,我们暴力真是太厉害辣
而其实早在题目数据约定中就给出了数据范围
如图
而这个数据范围就注定了不能用暴力做法来做,不然很轻易就可以TLE
我的想法是用树状数组来储存,思路同上,储存一个数前面比它大的数,blabla....,最后
用高斯定理分别计算每个小朋友的不高兴值相加就可以了
N = 1000010
def lowbit(x):
return x & -x
def add(x, y):
while x <= N:
tr[x] += y
x += lowbit(x)
def query(x):
res = 0
while x > 0:
res += tr[x]
x -= lowbit(x)
return res
if __name__ == '__main__':
n = int(input())
lst_friend = list(map(int, input().split()))
cmp = [0 for _ in range(n)]
tr = [0 for _ in range(N + 1)]
res = 0
for i in range(n): # 前面有几个比这个数大的数
lst_friend[i] += 1
cmp[i] += query(N) - query(lst_friend[i])
add(lst_friend[i], 1)
tr = [0 for _ in range(N + 1)]
for i in range(n - 1, -1, -1): # 后面还有几个比这个数小的数
cmp[i] += query(lst_friend[i] - 1)
add(lst_friend[i], 1)
for i in cmp:
res += (1 + i) * i // 2
print(res)