您的位置:首页 > 大数据 > 人工智能

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

2016-08-03 20:11 477 查看
题目链接: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: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,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.
1≤n≤50000
0≤Ai≤1e9

 

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

2016 Multi-University Training Contest 5

 

题目大意:

给n个数,问有多少个四元组,满足a≠b≠c≠d1≤a<b≤n,1≤c<d≤n,

Aa<Ab,Ac>Ad1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad打住

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

解题思路:

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

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

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

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

这里由于0≤Ai≤1e9,所以在传参不可能这么大,所以我们要预先的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
,c
;
int lmax
,lmin
,rmax
,rmin
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: