lowbit函数
def lowbit(x):
return x&(-x)
求前缀和
def query(x):
ans=0
while x:
ans+=tree[x]
x-=lowbit(x)
return ans
离散化
from bisect import *
def Discrete(a):
b=list(set(a))
b.sort()
ans=[]
for i in range(len(a)):
ans.append(bisect_left(b,a[i])+1)
return ans
区间内某个元素+y
def add(x,y):
while x<=n:
tree[x]+=y
x+=lowbit(x)
求逆序对
def lowbit(x):
return x&(-x)
#利用lowbit求前缀和
def query(x):
ans=0
while x:
ans+=tree[x]
x-=lowbit(x)
return ans
#离散化
from bisect import *
def Discrete(a):
b=list(set(a))
b.sort()
ans=[]
for i in range(len(a)):
ans.append(bisect_left(b,a[i])+1)
return ans
#a[x]+=y
def add(x,y):
while x<=n:
tree[x]+=y
x+=lowbit(x)
n=int(input())
a=list(map(int,input().split()))
a=[0]+Discrete(a)
tree=[0]*(n+1)
#对于每个a[j],统计前面有多少数字大于a[j]
#j-前面小于等于a[j]的数
ans=0
for j in range(1,n+1):
#比a[j]大的数对应的tree数组+1
add(a[j],1)
#求前缀和,就是求前面小于等于a[j]的数的数量
ans+=j-query(a[j])
print(ans)
例题
小朋友排队
题目描述
n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是 0。
如果某个小朋友第一次被要求交换,则他的不高兴程度增加 1,如果第二次要求他交换,则他的不高兴程度增加 2(即不高兴程度为 3),依次类推。当要求某个小朋友第 k 次交换时,他的不高兴程度增加 k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。
输入描述
输入描述
输入的第一行包含一个整数 n,表示小朋友的个数。
第二行包含 n 个整数 H1H2…Hn,分别表示每个小朋友的身高。
其中,1≤n≤105,0≤Hi≤106。
输出描述
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
运行限制
-
最大运行时间:1s
-
最大运行内存: 256M
解题思路
每一个小朋友的最小交换次数等于他左边比他高的人加上右边比他矮的人。
用树状数组做两次逆序对,一次正序处理,一次逆序处理。
from bisect import *
n=int(input())#人数
h=list(map(int,input().split()))#高度
def Discrete(a):
b=list(set(a))
b.sort()
ans=[]
for i in range(len(a)):
ans.append(bisect_left(b,a[i])+1)
return ans
def lowbit(x):
return x&-x
def add(x,y):
while x<=n:
tree[x]+=y
x+=lowbit(x)
def getsum(x):
s=0
while x>0:
s+=tree[x]
x-=lowbit(x)
return s
h=[0]+Discrete(h)
rever=[0]*(n+1)#逆序对数量
tree=[0]*(n+1)
for i in range(1,n+1):
rever[i]=getsum(n)-getsum(h[i])
add(h[i],1)
tree=[0]*(n+1)
for i in range(n,0,-1):
rever[i]+=getsum(h[i]-1)
add(h[i],1)
ans=0
for i in range(1,n+1):
ans+=int((1+rever[i])*rever[i]/2)
print(ans)