找出有多少个四元组(a,b,c,d)满足a≠b≠c≠d,a < b,c < d,Aa < Ab,Ac > Ad.
思路:
计算像a,b这样上升的有sm对,像c,d这样下降的有bg对,ans=la*lb。这样是有重复的,重复的就是a与c重合,a与d重合,b与c重合,b与d重合这四种情况。那么减去这四种情况就ok了。可以用树状数组预处理出每一位i的左边比a[i]大的有多少Lb[],小的有多少Ls[],右边比a[i]大的有多少Rb[],小的有多少Ls[]。最后ans减去Rs[i]*Rb[i]; Ls[i]*Lb[i]; Ls[i]*Rs[i]; Lb[i]*Rb[i] 就行了。
如何找sm只需从左到右 树状数组 枚举b点,求前面有多少个比他小的,就是sm // ab
找bg只需从右到左 树状数组 枚举c点,求后面有多少个比他小的,就是bg; //cd
其他的只需要树状数组求即可;
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=51000;
int tree[N];
int a[N];
int b[N];
int cnt[N];
int Ls[N],Lb[N],Rs[N],Rb[N];
int n;
int lowbit(int x){
return x&(-x);
}
int getsum(int x){
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
void add(int x,int d){
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int m=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(b+1,b+m+1,a[i])-b;
}
LL sm=0,bg=0;
memset(cnt,0,sizeof(cnt));///重复的点个数
memset(tree,0,sizeof(tree));
memset(Lb,0,sizeof(Lb));
memset(Rb,0,sizeof(Rb));
memset(Ls,0,sizeof(Ls));
memset(Rs,0,sizeof(Rs));
for(int i=1;i<=n;i++){
Ls[i]=getsum(a[i]-1);
Lb[i]=i-1-Ls[i]-cnt[a[i]];
add(a[i],1);
cnt[a[i]]++;
sm+=Ls[i];
}
memset(cnt,0,sizeof(cnt));
memset(tree,0,sizeof(tree));
for(int i=n;i>=1;i--){
Rs[i]=getsum(a[i]-1);
Rb[i]=n-i-Rs[i]-cnt[a[i]];
add(a[i],1);
cnt[a[i]]++;
bg+=Rs[i];
}
LL sum=sm*bg;
// cout<<sum<<endl;
// for(int i=1;i<=n;i++){
// cout<<Lb[i]<<" "<<Ls[i]<<" "<<Rb[i]<<" "<<Rs[i]<<endl;
// }
for(int i=1;i<=n;i++){
sum=sum-Ls[i]*Rs[i];
sum=sum-Ls[i]*Lb[i];
sum=sum-Rs[i]*Rb[i];
sum=sum-Lb[i]*Rb[i];
}
printf("%lld\n",sum);
}
return 0;
}