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; }