思路
要求互不相等的a,b,c,d
1. 满足
a<b
且
Aa<Ab
,即一个升序对
2. 满足
c<d
且
Ac>Ad
,即一个降序对
对于一个升序的序列,其逆序对的个数为
∑
每个数右侧小于这个数的个数
若一个数大于右侧的一个数,则右侧的这个数一定小于左侧的一个数,显然,升序对个数等于降序对
答案可以通过枚举
a
和
因为要求四个数两两不同,所以要减去以下四种情况:
1.
a
和
2.
a
和
3.
b
和
4.
b
和
可以用树状数组预处理出每个数右侧大于这个数的个数,右侧小于这个数的个数,左侧大于这个数的个数,左侧小于这个数的个数。
Trick:
1. 数据要做离散化处理
2. 可能有重复的数,在计算右边小或左边小(a、c)时不需要算进去,但是在去重时要予以考虑
代码
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define debug(a) printf("a =: %d\n",a);
const int INF=0x3f3f3f3f;
const int maxn=5e4+50;
const int Mod=1000000007;
const double PI=acos(-1);
typedef long long ll;
using namespace std;
int n;
int c[maxn];
int lowbit(int x){
return x&(-x);
}
void add(int pos,int ad){
for(;pos<=n;pos+=lowbit(pos))
c[pos]+=ad;
}
int query(int pos){
int ret=0;
for(;pos>0;pos-=lowbit(pos))
ret+=c[pos];
return ret;
}
int rg[maxn],rs[maxn],lg[maxn],ls[maxn];
int s[maxn],tmp[maxn];
void init(){
map<int,int> ma;
int cnt=1;
sort(tmp,tmp+n);
for(int i=0;i<n;i++){
if (!ma[tmp[i]]){
ma[tmp[i]]=cnt++;
}
}
for(int i=0;i<n;i++){
s[i]=ma[s[i]];
}
mem(c,0);
for(int i=n-1;i>=0;i--){
int t=s[i];
rs[i]=query(s[i]-1);
rg[i]=n-i-1-query(s[i]);
add(t,1);
// cout<<i<<" "<<rs[i]<<" "<<rg[i]<<endl;
}
mem(c,0);
for(int i=0;i<n;i++){
int t=s[i];
ls[i]=query(s[i]-1);
lg[i]=i-query(s[i]);
add(t,1);
// cout<<i<<" "<<ls[i]<<" "<<lg[i]<<endl;
}
}
ll solve(){
ll inc=0,dec=0;
ll ret=0;
for(int i=0;i<n;i++){
inc+=ls[i];
dec+=rs[i];
ret-=rg[i]*lg[i]+ls[i]*rs[i]+rg[i]*rs[i]+lg[i]*ls[i];
}
ret+=inc*dec;
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
while(scanf("%d",&n)!=EOF){
for(int i=0,t;i<n;i++){
scanf("%d",&t);
s[i]=tmp[i]=t;
}
init();
cout<<solve()<<"\n";
}
return 0;
}