题目描述
在完成了分配任务之后,西部314来到了楼兰古城的西部。
相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(‘V’),一个部落崇拜铁锹(‘∧’),他们分别用V和∧的形状来代表各自部落的图腾。
西部314在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了N个点,经测量发现这N个点的水平位置和竖直位置是两两不同的。
西部314认为这幅壁画所包含的信息与这N个点的相对位置有关,因此不妨设坐标分别为(1,y1),(2,y2),…,(n,yn),其中y1~yn是1到n的一个排列。
西部314打算研究这幅壁画中包含着多少个图腾。
如果三个点(i,yi),(j,yj),(k,yk)满足1≤i[HTML_REMOVED]yj,yj<yk,则称这三个点构成V图腾;
如果三个点(i,yi),(j,yj),(k,yk)满足1≤i[HTML_REMOVED]yk,则称这三个点构成∧图腾;
西部314想知道,这n个点中两个部落图腾的数目。因此,你需要编写一个程序来求出V的个数和∧的个数。
输入样例
5
1 5 3 2 4
输入样例
3 4
算法
(树状数组/前缀和) $O(n*logn(n))$
主要思路:
(1)对于“V”型:
对于每个yj坐标,求出在yj前面比yj大的,在yj后面比大的,这两部分直接相乘,得到以yj为最低点组成的“V”型的数目
(2)对于“∧” 型:
同理,求出在yj前后,比yj小的,然后相乘
(3)存储每个数出现的次数,cnt[yj]+=1。cnt[]数组是基本数组,树状数组tr[yj]是小于等于yj的数出现的次数累计值
时间复杂度:枚举n次,每次用到树状数组求区间和是log(n)
参考文献:https://www.acwing.com/video/633/
python 代码
N=2*10**5+10
def lowbit(x):
return x&(-x)
def add(x,v):
i=x
while i<=N:
tr[i]+=v
i+=lowbit(i)
def sum(x):
i=x
res=0
while i:
res+=tr[i]
i-=lowbit(i)
return res
n=int(input())
q=[0 for i in range(n+2)]
front_larger=[0 for i in range(n+2)]
front_less=[0 for i in range(n+2)]
back_larger=[0 for i in range(n+2)]
back_less=[0 for i in range(n+2)]
q[1:]=list(map(int,input().split()))
tr=[0 for i in range(N+2)]
for i in range(1,n+1):
front_larger[i]=sum(N)-sum(q[i]-1)
front_less[i]=sum(q[i]-1)
add(q[i],1)
tr=[0 for i in range(N+2)]
for i in range(n,0,-1):
back_larger[i]=sum(N)-sum(q[i])
back_less[i]=sum(q[i]-1)
add(q[i],1)
up_res,down_res=0,0
for i in range(1,n+1):
up_res+=(front_less[i]*back_less[i])
down_res+=(front_larger[i]*back_larger[i])
print(down_res,up_res)