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; } }
没有人不辛苦,只有人不喊疼