ch4201 楼兰图腾

题目链接:https://ac.nowcoder.com/acm/contest/1032/A

简单题意:给定序列a,分别求出ai<aj>ak和ai>aj<ak(i,j,k互不相同)的对数

考虑ai<aj>ak。用和求逆序对类似的方法,正反向两次枚举,分别求出对于每个aj(即枚举三个数中间的数)左边比它小的数和右边比它大的数各有多少个,分别为l[i]和r[i],则Σ(l[i]*r[i])就是答案。ai>aj<ak同理

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=2e5+10;
int l[N],r[N],c[N],a[N],n,m,i,j,k;

void add(int x,int y){
	for (int i=x;i<=n;i+=(i&-i)) c[i]+=y;
}
int ask(int x){
	int res=0;
	for (int i=x;i>0;i-=(i&-i)) res+=c[i];
	return res;
}

int main(){
	scanf("%d",&n);
	for (i=1;i<=n;i++) scanf("%d",&a[i]);
	for (i=1;i<=n;i++) {
	  l[i]=ask(n)-ask(a[i]); add(a[i],1);
	}
	memset(c,0,sizeof(c));
	for (i=n;i>=1;i--){
	  r[i]=ask(n)-ask(a[i]); add(a[i],1);
	}
	ll ans1=0;
	for (i=1;i<=n;i++) ans1+=(l[i]*r[i]);
	memset(c,0,sizeof(c));
	for (i=1;i<=n;i++){
	  l[i]=ask(a[i]-1); add(a[i],1);
	}
	memset(c,0,sizeof(c));
	for (i=n;i>=1;i--){
	  r[i]=ask(a[i]-1); add(a[i],1);
	}
	ll ans2=0;
	for (i=1;i<=n;i++) ans2+=(l[i]*r[i]);
	printf("%lld %lld",ans1,ans2);
	return 0; 
}

  

posted @ 2020-09-06 00:16  coastal_taipan  阅读(124)  评论(0编辑  收藏  举报