World is Exploding
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,A
a
<A
b
,A
c
>A
d![]()
.
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 A
1
,A
2
⋯A
n![]()
.
1≤n≤50000
0≤A
i
≤1e9
Each test case begin with an integer n in a single line.
The next line contains n integers A
1≤n≤50000
0≤A
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
题意很明确,就是让我们求一个四元组,满足 a<b并且c<d.
解题思路:可以求出所有的四元组数目减去不符合条件四元组的数目,就可以得到我们需要的了。具体怎么实现呢,做这个题顺便学习了一下树状数组(百度百科有很详细的解释),真是很神奇的东西。但是这道题确实让我转了很大的圈子。具体解释详见代码。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
long long a[50001],b[50001],c[50001],aa[50001];
long long yx[50001],yd[50001],zx[50001],zd[50001];
long long n;
long long num; // 这里全部用 long long 是为了省事儿
long long get_k(long long k)
{
return k&-k;
}
void add(long long pos,long long val)
{
while(pos<=n)
{
c[pos] += val; // 数组c是用来存储树状数组的值
pos += get_k(pos);
}
return ;
}
long long get_sum(long long pos)
{
long long ans = 0;
while(pos>0)
{
ans += c[pos];
pos -= get_k(pos);
}
return ans;
} // 以上三个函数为对树状数组的操作 ,百度百科可以很详细的学习树状数组。
int main()
{
while(scanf("%lld",&n)!=EOF)
{
memset(c,0,sizeof(c));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(yx,0,sizeof(yx));
memset(yd,0,sizeof(yd));
memset(zx,0,sizeof(zx));
memset(zd,0,sizeof(zd));
for(int i=1;i<=n;i++)
{
scanf("%lld", &a[i]);
b[i] = a[i];
}
sort(b+1,b+1+n);
num = unique(b+1,b+1+n) - (b+1); //排序去重,方便离散化,其实这一步有没有都能AC。
long long sum1,sum2;
sum1 = sum2 = 0;
//两个for循环,正反各一次
for(int i=1;i<=n;i++)
{
long long pos = lower_bound(b+1,b+1+num,a[i]) - b; // 每次找到a[i]的位置,如果没用unique,num就改为n
add(pos,1);
zx[i] = get_sum(pos-1); //左边比a[i]小的数目
zd[i] = i - get_sum(pos);//左边比a[i]大的数目
}
memset(c,0,sizeof(c)); // 反向循环的时候树状数组要清空重建
for(int i=n; i>=1; i--)
{
long long pos = lower_bound(b+1,b+1+n,a[i]) - b;
add(pos,1);
yx[i] = get_sum(pos-1); // 右边比a[i]小的数目
yd[i] = n-i+1 - get_sum(pos); //右边比a[i]大的数目
sum1 += yx[i];
sum2 += yd[i];
}
long long pp = sum1 * sum2; // 所有的四元组
/*重复的情况有四种
即 ac重复,ad重复,bc重复,bd重复
*/
for(int i=1;i<=n;i++)
{
pp -= zx[i]*yx[i];
pp -= zd[i]*yd[i];
pp -= zx[i]*zd[i];
pp -= yx[i]*yd[i];
}
printf ("%lld\n",pp);
}
return 0;
}
水波