HDU5792 World is Exploding(树状数组+容斥原理)

根据对题目的观察,我们可以发现本题其实可以抽象成正序对和逆序对的个数的题目

这就能让我们联想到使用树状数组来解决问题

另外本题需要离散化,因为数据过大。

我们可以先求取所有情况,减去不合法的情况,也就是所谓的容斥原理,那么那些是不满足的呢?

我们从题目看出他要是四元组,而我们用乘法原理求出的情况,包含很多满足情况的三元组

比如Aa<=Ab==Ad<Ac这种情况只有三元组,而我们在计算中也算过了,所以把这些情况减去即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int a[N];
int n;
int tr[N];
int li[N],ri[N];
int lx[N],rx[N];
vector<int> num;
int find(int x){
    return lower_bound(num.begin(),num.end(),x)-num.begin()+1;
}
int lowbit(int x){
    return x&-x;
}
void add(int x,int c){
    int i;
    for(i=x;i<=n;i+=lowbit(i))
    tr[i]+=c;
}
int sum(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i))
        ans+=tr[i];
    return ans;
}
int main(){
    int i;
    while(cin>>n){
        memset(li,0,sizeof li);
        memset(ri,0,sizeof ri);
        memset(rx,0,sizeof rx);
        memset(lx,0,sizeof lx);
        memset(tr,0,sizeof tr);
        num.clear();
        for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        num.push_back(a[i]);
    }
    sort(num.begin(),num.end());
    num.erase(unique(num.begin(),num.end()),num.end());
    ll ans1=0;
    ll ans2=0;
    ll ans3=0;
    for(i=1;i<=n;i++){
        
        int pos=find(a[i]);
        li[i]=sum(pos-1);
        lx[i]=sum(n)-sum(pos);
        add(pos,1);
    }
    memset(tr,0,sizeof tr);
    for(i=n;i>=1;i--){
        int pos=find(a[i]);
        ri[i]=sum(pos-1);
        rx[i]=sum(n)-sum(pos);
        add(pos,1);
    }
    for(i=1;i<=n;i++){
        ans3+=1ll*li[i]*ri[i];
        ans3+=1ll*lx[i]*rx[i];
        ans3+=1ll*li[i]*lx[i];
        ans3+=1ll*rx[i]*ri[i];
        ans1+=li[i];
        ans2+=ri[i];
    }
    cout<<ans1*ans2-ans3<<endl;
    }
}
View Code

 

posted @ 2020-02-04 15:48  朝暮不思  阅读(138)  评论(0编辑  收藏  举报