Ping pong
题目大意:一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术。每个人都有一个不同的技能值ai。每场比赛需要三个人:两名选手,一名裁判。他们有一个奇怪的规定,即裁判必须住在两名选手的中间,并且技能值也在两名选手之间。问一共能组织多少场比赛。输入第一行表示共有T组测试数据,每组数据占一行,先输入整数n(3<=n<=20000),后面跟着输入n个不同的整数,即a1,a2,a3...an(1<=ai<=100000),按照从左到右的顺序给出每个乒乓球爱好者的技能值。
解决方法:树状数组解决,考虑第i个人当裁判的情况。假设a1到ai-1中有ci个比ai小,那么就有(i-1)-ci个比ai大;同理,假设a(i+1)到an中有di个比ai小,则其中就有n-i-di个比其大,所以以ai为裁判的比赛场数为:ci*(n-i-di)+di*(i-1-ci),因此先用树状数组求每个数前面比其小的数字的数目,再反向求其后面比它小的数目,即可得到答案。
AC代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e6 + 5;
const ll mod = 1e9+7;
int C1[maxn];
int C2[maxn];
int arr[maxn]; //存技能值
int sum11[maxn]; //存的每个数前面的比其小的数目
int sum22[maxn]; //存的每个数后面比其小的数目
int n;
int lowbit(int x)
{
return x&(-x);
}
void add1(int x,int d)
{
while(x<=100000)
{
C1[x]+=d;
x+=lowbit(x);
}
}
int sum1(int x)
{
int ret=0;
while(x>0)
{
ret+=C1[x];
x-=lowbit(x);
}
return ret;
}
void add2(int x,int d)
{
while(x<=100000)
{
C2[x]+=d;
x+=lowbit(x);
}
}
int sum2(int x)
{
int ret=0;
while(x>0)
{
ret+=C2[x];
x-=lowbit(x);
}
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
//freopen("out.txt", "w", stdout);
ios::sync_with_stdio(0),cin.tie(0);
int T;
cin>>T;
while(T--)
{
ms(C1);ms(C2);ms(arr);ms(sum11);ms(sum22);
cin>>n;
rep(i,1,n) {
cin>>arr[i];
add1(arr[i],1);
sum11[i]=sum1(arr[i]-1);
}
lep(i,n,1) {
add2(arr[i],1);
sum22[i]=sum2(arr[i]-1);
}
ll ans=0;
rep(i,1,n) {
ll c1=sum11[i];
ll d1=sum22[i];
ans+=c1*(n-i-d1)+d1*(i-1-c1);
}
cout<<ans<<endl;
}
return 0;
}