对应HDU题目:点击打开链接
思路:举个例子(等级不一定是1~N)
1 3 7 6 9 8 5
如果6是裁判,那左边等级比他低的人数(顺序数)a= 2;右边等级比他高的人数(顺序数)b = 2;左边等级比他高的人数(逆序数)c= 1;右边等级比他低的人数(逆序数)d = 1;
所以6做裁判的话就能组成a*b + c*d = 5个不同的比赛。
从左到右for一遍,把每个人做裁判能组成的比赛数目加起来就是结果。
逆序数与顺序数的求解可用树状数组
具体实现代码:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
const int MAXN=20000+10;
using namespace std;
int a[MAXN];
int highl[MAXN];//highl[i]表示第i个数左边比a[i]大的数的个数
int highr[MAXN];//highr[i]表示第i个数右边比a[i]大的数的个数
int lowl[MAXN];//lowl[i]表示第i个数左边比a[i]小的数的个数
int lowr[MAXN];//lowr[i]表示第i个数右边比a[i]小的数的个数
int c[MAXN*5];
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int num)
{
while(x <= 5*MAXN-2)
{
c[x] += num;
x += lowbit(x);
}
}
int sum(int x)
{
int res = 0;
while(x > 0)
{
res += c[x];
x -= lowbit(x);
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
int T;
scanf("%d", &T);
while(T--)
{
int n;
memset(c,0,sizeof(c));
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d", a+i);
int x = a[i];
highl[i] = sum(5*MAXN) - sum(x);
lowl[i] = sum(x);
update(x,1);
}
memset(c,0,sizeof(c));
for(int i=n-1; i>=0; i--){
int x = a[i];
highr[i] = sum(5*MAXN) - sum(x);
lowr[i] = sum(x);
update(x,1);
}
long long Sum = 0;
for(int i=0; i<n; i++){//乘法原理和加法原理
Sum += (long long) highl[i] * lowr[i];
Sum += (long long) lowl[i] * highr[i];
}
printf("%lld\n", Sum);
}
return 0;
}