(one data one problem)hdu-5792 World is Exploding (树状数组)

来源:互联网 发布:数据地图网 编辑:程序博客网 时间:2024/06/03 11:18

题目链接:点击打开链接

Problem Description
Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: abcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad.
 

Input
The input consists of multiple test cases. 
Each test case begin with an integer n in a single line.

The next line contains n integers A1,A2An.
1n50000
0Ai1e9
 

Output
For each test case,output a line contains an integer.
 

Sample Input
42 4 1 341 2 3 4
 

Sample Output
10
题目大意:给出一个长为n的序列,问有多少四元组(a,b,c,d)满足a!=b!=c!=d,1<=a<b<=n

题解:

首先要找到这样的四元组是怎么来的,可以先把四元组拆分一下那就是两个二元组,二元组就好求了。就是求一个两个逆序数。那么一个升序,一个降序的二元组的个数相乘就是四元组的了。但是这样乘的话肯定会有用到重复的数字的。因为根据题目要求可以在求逆序数的时候让a!=b。所以在乘的过程中相等会有a=c,a=d,b=c,b=d这四种情况。那么怎么去重以及怎么求呢?

对于第i个数,可以求出它的左面比他大的数的个数,左面比他小的个数,右面比他小的和比他大的。在求升序对的时候就是找出每个比i小的加起来就可以了。那么降序就是左面比他大的呗!相乘就是总的四元组的个数(没有去重的情况下的)。

现在去重。比如先看一下当a==c的时候,那么也就是a和c此时是一个数,那么看看b和d放在什么位置呢?

 因为b>a,所以b在a的右面,d要大于c所以d也要在c的右面。也就是a(c),(b,d),回到题意,如果把a(c)作为第i个值得话。Ai<Ab(升序),,Ai>Ad(降序)。可以看出这是重复的部分。要把它去掉,也就是把i的右面比它大的(以i升序的部分)乘以 右面比它小的(以i降序的部分)。同理其他的也只这样处理。

#include <iostream>#include <bits/stdc++.h>using namespace std;typedef long long LL;LL a[50050],c[50050];LL b[50050];LL lmx[50050],rmx[50050],lmn[50050],rmn[50050];map<LL,LL>mp;void add(LL i,LL x,LL n){    while(i<=n)    {        c[i]+=x;        i+=i&(-i);    }}LL sum(LL i){    LL s=0;    while(i>=1)    {        s+=c[i];        i-=i&(-i);    }    return s;}int main(){    LL n;    while(~scanf("%lld",&n))    {        LL ans=0;        mp.clear();        for(LL i=1;i<=n;i++)        {            scanf("%lld",&a[i]);            b[i]=a[i];            //if(!mp[a[i]])mp[a[i]]=++ans;        }        sort(b+1,b+n+1);        for(LL i=1;i<=n;i++)        {            if(!mp[b[i]])mp[b[i]]=++ans;        }        for(LL i=1;i<=n;i++)        {            a[i]=mp[a[i]];            //cout<<a[i]<<" ";        }        //cout<<endl;        LL oto=0;        memset(c,0,sizeof(c));        for(LL i=1;i<=n;i++)        {            lmn[i]=sum(a[i]-1);            lmx[i]=sum(ans)-sum(a[i]);            oto+=lmn[i];            add(a[i],1,ans);            //cout<<lmn[i]<<" "<<lmx[i]<<endl;        }        //cout<<"---------------"<<endl;        memset(c,0,sizeof(c));        for(LL i=n;i>=1;i--)        {            rmn[i]=sum(a[i]-1);            rmx[i]=sum(ans)-sum(a[i]);            add(a[i],1,ans);            //cout<<rmn[i]<<" "<<rmx[i]<<endl;        }        //cout<<"-------------------"<<endl;        LL ant=0;        for(LL i=1;i<=n;i++)        {            ant+=oto*lmx[i];        }        ///a=c;        for(LL i=1;i<=n;i++)        {            ant-=(rmx[i]*rmn[i]);        }        ///a=d;        for(LL i=1;i<=n;i++)        {            ant-=(rmx[i]*lmx[i]);        }        ///b=c;        for(LL i=1;i<=n;i++)        {            ant-=(lmn[i]*rmn[i]);        }        ///b=d;        for(LL i=1;i<=n;i++)        {            ant-=(lmn[i]*lmx[i]);        }        printf("%lld\n",ant);    }    return 0;}


0 0