(HDU 5792)2016 Multi-University Training Contest 5 World is Exploding (逆序数、顺序数、树状数组)

来源:互联网 发布:双色球历史数据库下载 编辑:程序博客网 时间:2024/05/16 13:45

思路

要求互不相等的a,b,c,d
1. 满足a<bAa<Ab,即一个升序对
2. 满足c<dAc>Ad,即一个降序对
对于一个升序的序列,其逆序对的个数为每个数右侧小于这个数的个数
若一个数大于右侧的一个数,则右侧的这个数一定小于左侧的一个数,显然,升序对个数等于降序对
答案可以通过枚举ac来得到。
因为要求四个数两两不同,所以要减去以下四种情况:
1. ac重合,减去ni=1右侧大*右侧小
2. ad重合,减去ni=1右侧大*左侧大
3. bc重合,减去ni=1右侧小*左侧小
4. bd重合,减去ni=1左侧大*右侧大
可以用树状数组预处理出每个数右侧大于这个数的个数,右侧小于这个数的个数,左侧大于这个数的个数,左侧小于这个数的个数。

Trick:
1. 数据要做离散化处理
2. 可能有重复的数,在计算右边小或左边小(a、c)时不需要算进去,但是在去重时要予以考虑

代码

#include <bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define rep(i,a,b) for(int i=a;i<b;i++)#define debug(a) printf("a =: %d\n",a);const int INF=0x3f3f3f3f;const int maxn=5e4+50;const int Mod=1000000007;const double PI=acos(-1);typedef long long ll;using namespace std;int n;int c[maxn];int lowbit(int x){    return x&(-x);}void add(int pos,int ad){    for(;pos<=n;pos+=lowbit(pos))        c[pos]+=ad;}int query(int pos){    int ret=0;    for(;pos>0;pos-=lowbit(pos))        ret+=c[pos];    return ret;}int rg[maxn],rs[maxn],lg[maxn],ls[maxn];int s[maxn],tmp[maxn];void init(){    map<int,int> ma;    int cnt=1;    sort(tmp,tmp+n);    for(int i=0;i<n;i++){        if (!ma[tmp[i]]){            ma[tmp[i]]=cnt++;        }    }    for(int i=0;i<n;i++){        s[i]=ma[s[i]];    }    mem(c,0);    for(int i=n-1;i>=0;i--){        int t=s[i];        rs[i]=query(s[i]-1);        rg[i]=n-i-1-query(s[i]);        add(t,1);    //  cout<<i<<" "<<rs[i]<<" "<<rg[i]<<endl;    }    mem(c,0);    for(int i=0;i<n;i++){        int t=s[i];        ls[i]=query(s[i]-1);        lg[i]=i-query(s[i]);        add(t,1);    //  cout<<i<<" "<<ls[i]<<" "<<lg[i]<<endl;    }}ll solve(){    ll inc=0,dec=0;    ll ret=0;    for(int i=0;i<n;i++){        inc+=ls[i];        dec+=rs[i];        ret-=rg[i]*lg[i]+ls[i]*rs[i]+rg[i]*rs[i]+lg[i]*ls[i];    }    ret+=inc*dec;    return ret;}int main(){    #ifndef ONLINE_JUDGE        freopen("in.txt","r",stdin);    #endif    while(scanf("%d",&n)!=EOF){        for(int i=0,t;i<n;i++){            scanf("%d",&t);            s[i]=tmp[i]=t;        }        init();        cout<<solve()<<"\n";    }    return 0;}
0 0
原创粉丝点击