hdu 5792(树状数组,容斥) World is Exploding

时间:2023-03-09 04:17:21
hdu 5792(树状数组,容斥) World is Exploding

hdu 5792

要找的无非就是一个上升的仅有两个的序列和一个下降的仅有两个的序列,按照容斥的思想,肯定就是所有的上升的乘以所有的下降的,然后再减去重复的情况。

先用树状数组求出lx[i](在第 i 个数左边的数中比它小的数的个数),ld[i](在第 i 个数左边的数中比它大的数的个数),rx[i](在第 i 个数右边的数中比它小的数的个数)

,rd[i](在第 i 个数右边的数中比它大的数的个数)。然后重复的情况无非就是题目中a与c重合(rx[i]*rd[i]),a与d重合(rd[i]*ld[i]),b与c重合(lx[i]*rx[i]),b与

d重合(lx[i]*ld[i])

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std; typedef long long ll;
const int M = 5e4 + ;
int a[M],b[M],bit[M],has[M];
ll ld[M],lx[M],rd[M],rx[M]; int lowbit(int x){return x&-x;} int sum(int x){
int ret=;
while (x>)
ret+=bit[x],x-=lowbit(x);
return ret;
} void add(int x,int d){
while (x<=M)
bit[x]+=d,x+=lowbit(x);
} int main()
{
int n;
while (~scanf("%d",&n)){
for (int i= ; i<=n ; i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+,b+n+);
int m=unique(b+,b+n+)-b;
//cout<<m<<endl;
m--;
for (int i= ; i<=n ; i++){
a[i]=lower_bound(b+,b+m+,a[i])-b;
}
memset(lx,,sizeof(lx));
memset(ld,,sizeof(ld));
memset(rd,,sizeof(rd));
memset(rx,,sizeof(rx));
memset(bit,,sizeof(bit));
memset(has,,sizeof(has));
ll ans=,ans1=,ans2=;
//cout<<"xx"<<endl;
for (int i= ; i<=n ; i++){
has[a[i]]++;
lx[i]=sum(a[i]-);
ld[i]=(i-has[a[i]])-lx[i];
add(a[i],);
}
memset(bit,,sizeof(bit));
memset(has,,sizeof(has));
for (int i=n ; i>= ; i--){
has[a[i]]++;
rx[i]=sum(a[i]-);
rd[i]=(n-i+-has[a[i]])-rx[i];
add(a[i],);
ans1+=rx[i];
ans2+=rd[i];
}
ans=ans1*ans2;
for (int i= ; i<=n ; i++){
ans-=rd[i]*ld[i];
ans-=rx[i]*lx[i];
ans-=rd[i]*rx[i];
ans-=ld[i]*lx[i];
}
printf("%I64d\n",ans);
}
return ;
}