题目链接: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;
}