hdu5792树状数组+容斥

来源:互联网 发布:淘宝卖农产品赚钱吗 编辑:程序博客网 时间:2024/06/05 19:21

http://acm.hdu.edu.cn/showproblem.php?pid=5792

思路:用树状数组统计每个数前面比他小的数lmin,大的数lmax,后面比他小的数rmin,大的数rmax,不考虑条件总的数量是lmin,lmax的和,去掉不满足的:a=c rmax[]*rmin[] ,a=d lmax[]*rmax[] , b=c lmin[]*rmin[] ,b=d lmin[]*lmax[]就是答案

#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <map>#include <algorithm>using namespace std;typedef long long ll;const int maxn=50005;int a[maxn],c[maxn];int lmin[maxn],lmax[maxn],rmin[maxn],rmax[maxn];vector<int>V;map<int,int>M;int lowbit(int x){    return x&(-x);}void update(int x,int add){    while(x<maxn)    {        c[x]+=add;        x+=lowbit(x);    }}int sum(int x){    int ret=0;    while(x)    {        ret+=c[x];        x-=lowbit(x);    }    return ret;}int main(){    int n;    while(~scanf("%d",&n))    {        memset(c,0,sizeof(c));        V.clear();        M.clear();        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            V.push_back(a[i]);        }        sort(V.begin(),V.end());        V.erase(unique(V.begin(),V.end()),V.end());//去重        for(int i=0;i<V.size();i++)//离散化        M[V[i]]=i+1;        for(int i=1;i<=n;i++)        a[i]=M[a[i]];        ll ans=0,ans1=0,ans2=0;        for(int i=1;i<=n;i++)        {            update(a[i],1);            lmin[i]=sum(a[i]-1);////当前位置左边比他小的有多少个            lmax[i]=sum(maxn-1)-sum(a[i]);////已经出现的数肯定是他左边的数,在这个时候记录数轴上有多少个数再减去小于等于的,就是大于的了        }        memset(c,0,sizeof(c));        for(int i=n;i>=1;i--)        {            update(a[i],1);            rmin[i]=sum(a[i]-1);            rmax[i]=sum(maxn-1)-sum(a[i]);        }        for(int i=1;i<=n;i++)        {            ans1+=lmin[i];//升序的对数            ans2+=lmax[i];//逆序的对数        }        ans=ans1*ans2;        for(int i=1;i<=n;i++)        ans-=(rmax[i]*rmin[i]+lmax[i]*rmax[i]+lmin[i]*rmin[i]+lmin[i]*lmax[i]);        cout<<ans<<endl;    }    return 0;}
0 0