码迷,mamicode.com
首页 > 编程语言 > 详细

hdu 5792 World is Exploding(2016 Multi-University Training Contest 5——树状数组)

时间:2016-08-03 20:30:13      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5792

World is Exploding

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 643    Accepted Submission(s): 306


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,A2?An.
1n50000
0Ai1e9
 

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

Sample Input
4 2 4 1 3 4 1 2 3 4
 

Sample Output
1 0
 

Author
ZSTU
 

Source
 

题目大意:

给n个数,问有多少个四元组,满足abcd1a<bn,1c<dn,

Aa<Ab,Ac>Ad1a<bn,1c<dn,Aa<Ab,Ac>Ad1a<bn,1c<dn,Aa<Ab,Ac>Ad打住

这里a,b,c,d两两不相等。

解题思路:

先找出逆序对和升序对,把两个得到的数乘起来在减去不合法的即可。

其中不合法的就是长度为3的,有一些重复计算了的减掉。

四个数组,lmax表示他左边有多少个比他大的,lmin表示左边有多少小的

rmax,rmin分别表示右边有多少大的和小的。

这里由于0Ai1e9,所以在传参不可能这么大,所以我们要预先的a[i]这个数组进行离散化处理。

离散化的处理方法就是:找到相应的序列,对他排序,在给每一个重新复制,从1开始,这样最多也就50000,。

这里做的原因是我们这个题目和数值没有关系,至于前后左右的大小有关。


详见代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

#define N 50010
#define ll long long

int a[N],c[N];
int lmax[N],lmin[N],rmax[N],rmin[N];
vector<int>V;
map<int,int>M;

int lowbit(int k)
{
    return k&((k)xor(k-1));
}

void add(int num,int k)
{
    while (k<N)
    {
        c[k]+=num;
        k+=lowbit(k);
    }
}

int sum(int k)
{
    int s=0;
    while (k)
    {
        s+=c[k];
        k-=lowbit(k);
    }
    return s;
}

int main()
{
    int n;
    ll s1,s2,s,cnt,ans;
    while (~scanf("%d",&n))
    {
        s1=s2=cnt=0;
        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]];

        memset(c,0,sizeof(c));
        for (int i=1; i<=n; i++)
        {
            add(1,a[i]);
            lmin[i]=sum(a[i]-1);//当前位置左边比他小的有多少个
            lmax[i]=sum(N-1)-sum(a[i]);//已经出现的数肯定是他左边的数,在这个时候记录数轴上有多少个数再减去小于等于的,就是大于的了

        }
        memset(c,0,sizeof(c));
        for (int i=n; i>=1; i--)
        {
            add(1,a[i]);
            rmin[i]=sum(a[i]-1);
            rmax[i]=sum(N-1)-sum(a[i]);
        }
        for (int i=1; i<=n; i++)
        {
            s1+=lmin[i];//升序的对数
            s2+=lmax[i];//逆序的对数
        }
        s=s1*s2;
       // cout<<s<<endl;
        for (int i=1;i<=n;i++)
        {
            cnt+=lmax[i]*lmin[i]+rmax[i]*rmin[i]+lmax[i]*rmax[i]+lmin[i]*rmin[i];
        }
        //cout<<cnt<<endl;
        ans=s-cnt;
        printf ("%lld\n",ans);
    }
    return 0;
}






hdu 5792 World is Exploding(2016 Multi-University Training Contest 5——树状数组)

标签:

原文地址:http://blog.csdn.net/qiqi_skystar/article/details/52106859

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!