您的位置:首页 > 理论基础 > 数据结构算法

爆裂吧世界(world)

2016-08-06 17:23 281 查看
爆裂吧世界(world/1S/64M)

【题目描述】

给你一个长度为n的数列A,请你计算里面有多少个四元组(a,b,c,d)满足:

a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>Ad

【输入格式】

输入文件第一行有一个整数N,第二行有N个整数A1,A2⋯An

【输出格式】

输出文件仅一行,为一个整数,表示满足条件的四元组的数量

【输入1】

4

2 4 1 3

【输出1】

1

【输入2】

4

1 2 3 4

【输出2】

0

【数据约定】

15% n<=100

100%n<=50000

A在int范围里

【解题思路】

15分解法:O(n^4)暴力

100分解法:离散化+树状数组+容斥原理+乘法原理

其实,这一题与树状数组求逆序对差不多。首先,求出符合(a,b)与(c,d)的对数,根据乘法原理,再相乘。但要注意a,b,c,d互不相等。所以要分情况。

不可能:a=b,c=d 因为a<b&&c>d;

第1种:a=c small_left * small_right

第2种:a=d small_left * big_left

第3种:b=c big_right * small_right

第4种:b=d big_left *big_right

所以,只要减去这四种重复的情况就可以了。(注意用long long)

【程序】

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
const int Maxn = 50010;

int n;

#define down(a) for(int i=1;i<=n/2;i++) swap(a[i],a[n-i+1]);
#define lowbit(x) x & -x

struct Tnode{
int x,y;
}b[Maxn];

int a[Maxn];

int tr[Maxn];
int bl[Maxn] , br[Maxn] , sl[Maxn] , sr[Maxn];

bool cmp(Tnode x,Tnode y)
{
return x.x < y.x;
}

LL Sum(int x)
{
int sum = 0;
for( ;x;x-=lowbit(x)) sum += tr[x];
return sum;
}
void Add(int x)
{
for( ;x<=n;x+=lowbit(x)) tr[x] ++;
}

int main()
{
freopen("world.in","r",stdin);
freopen("world.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i].x);
b[i].y = i;
}
sort(b+1,b+n+1,cmp);
int tt = 0;
for(int i=1;i<=n;i++)
{
if(i!=1 && b[i].x == b[i-1].x) tt--;
tt++;
a[b[i].y] = tt;
}

for(int i=1;i<=n;i++)
{
sl[i] = Sum(a[i]-1);
bl[i] = Sum(n) - Sum(a[i]);
Add(a[i]);
}

down(a);
memset(tr,0,sizeof(tr));

for(int i=1;i<=n;i++)
{
sr[i] = Sum(a[i]-1);
br[i] = Sum(n) - Sum(a[i]);
Add(a[i]);
}

down(sr); down(br);

LL ab = 0 , cd = 0 , rc = 0;

for(int i=1;i<=n;i++)
{
ab += sl[i]; cd += bl[i];
rc += sl[i] * sr[i]
+ sl[i] * bl[i]
+ br[i] * sr[i]
+ bl[i] * br[i]
;
}
LL ans = ab * cd - rc;
printf("%I64d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息