hdu 5792(离散化+树状数组+容斥)
先算出所有组合的数量,再容斥去重,数据太大,树状数组存不下,所以要提前离散化一下
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; const int maxn=50000+100; typedef long long ll; int a[maxn],b[maxn],c[maxn]; int ln[maxn],lx[maxn];//[1,i-1]比a[i]小和比a[i]大的数的数量 int rn[maxn],rx[maxn];//[i+1,n]比a[i]小和比a[i]大的数的数量 int n; void add(int x) { for(int i=x;i<=n;i+=i&-i) c[i]+=1; } int sum(int x) { int ans=0; for(int i=x;i>=1;i-=i&-i) ans+=c[i]; return ans; } void init() { memset(b,0,sizeof(b)); } int main() { while(~scanf("%d",&n)) { init(); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); int m=unique(b+1,b+1+n)-(b+1);//去重 for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+m,a[i])-b;//离散化,存了排序后的位置,因为原a[i]过大 ll sum1=0,sum2=0; memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { ln[i]=sum(a[i]-1); lx[i]=sum(m)-sum(a[i]); sum1+=ln[i]*1LL; sum2+=lx[i]*1LL; add(a[i]); } ll ans=sum1*sum2;//全部组合的数量 memset(c,0,sizeof(c)); for(int i=n;i>=1;i--) { rn[i]=sum(a[i]-1); rx[i]=sum(m)-sum(a[i]); add(a[i]); } //a=c,b!=d for(int i=1;i<=n;i++) { ll num1=rx[i]*1LL; ll num2=rn[i]*1LL; ans-=num1*num2; } //c=b,a!=d for(int i=1;i<=n;i++) { ll num1=ln[i]*1LL; ll num2=rn[i]*1LL; ans-=num1*num2; } //a=d,b!=c for(int i=1;i<=n;i++) { ll num1=lx[i]*1LL; ll num2=rx[i]*1LL; ans-=num1*num2; } //b=d,a!=c for(int i=1;i<=n;i++) { ll num1=lx[i]*1LL; ll num2=ln[i]*1LL; ans-=num1*num2; } printf("%lld\n",ans); } return 0; }