题意:N个乒乓球爱好者,每场比赛3个人,1个裁判2个选手,裁判得在2名选手的中间,而且裁判的能力值也在2名选手中间,问能组织多少比赛。
做法:看大白书看到的题目。没想出来,是看分析才理解的,枚举裁判所在的位置,然后左边比他小的乘以右边比他大的加上右边比他大乘以左边比他小的是当前裁判所在位置能组织的比赛,所以要开一个大小为能力值最大值的树状数组,然后从前往后是找左边比他小的选手,加一个求一次前缀和,再从后往前,也是加一个求一次,最后在2到n-1范围进行乘法和累加就可以求出答案。
AC代码:
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<ctime>
using namespace std;
#define ll long long
#define MOD 1000000007
int a[20005],c[100005];
int x[20005],y[20005];
int m;
int lowbit(int x)
{
return x&(-x);
}
int sum(int x)
{
int ret = 0;
while(x>0)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
void add(int x, int d)
{
while(x<=m)
{
c[x] += d;
x += lowbit(x);
}
}
int main()
{
//freopen("input.txt","r",stdin);
// freopen("o.txt","w",stdout);
int i,t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(c,0,sizeof(c));
m = 0;
for(i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
m = max(m,a[i]);
}
ll ans=0;
ll a1,b1;
add(a[1],1);
for(i = 2; i <= n-1; i++)
{
x[i] = sum(a[i]-1);
add(a[i],1);
}
memset(c,0,sizeof(c));
add(a[n],1);
for(i = n-1; i >= 2; i--)
{
y[i] = sum(a[i]-1);
add(a[i],1);
}
for(i = 2; i<= n-1; i++)
ans += (ll)x[i]*(ll)(n-i-y[i]) + (ll)y[i]*(ll)(i-1-x[i]);
printf("%lld\n",ans);
}
return 0;
}