题目链接:点击打开链接
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
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题目大意:给出一个长为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;
}