题目链接
https://vjudge.net/problem/UVALive-4329
题意
一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术。每个人都有一个不同的技能值ai。每场比赛需要3个人:两名选手,一名裁判。他们有一个奇怪的规定,即裁判必须住在两名选手的中间,并且技能值也在两名选手之间。问一共能组织多少种比赛。
分析
枚举裁判从2号到N-1号,求出裁判的左边有多少人比其技能值小,裁判的右边有多少人比裁判的技能值大;或者左边的人比裁判的技能值大,右边的人比裁判的技能值小。
这样,问题就变成了逆序数问题了。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxv=1e5+100;
const int maxn=2e4+100;
typedef long long ll;
int tree[maxv],a[maxn],c[maxn],f[maxn],s[maxn],l[maxn];
int lowbit(int i)
{
return i&(-i);
}
void add(int i,int x)//第i位增加x
{
while(i<maxv)
{
tree[i]+=x;
i+=lowbit(i);//为了防止死循环,i不能为0
}
}
int sum(int i)//前i个数之和
{
ll ans=0;
while(i)
{
ans+=tree[i];
i-=lowbit(i);
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int N;
ll ans=0;
cin>>N;
for(int i=1;i<=N;i++)
cin>>a[i],a[i]++;
memset(tree,0,sizeof(tree));
for(int i=1;i<=N;i++)
{
add(a[i],1);
c[i]=sum(a[i]-1);
f[i]=i-1-c[i];
}
memset(tree,0,sizeof(tree));
for(int i=N;i>=1;i--)
{
add(a[i],1);
s[i]=sum(a[i]-1);
l[i]=N-i-s[i];
}
for(int i=2;i<=N-1;i++)
{
ans+=c[i]*l[i]+f[i]*s[i];
}
cout<<ans<<endl;
}
return 0;
}