题意:有N个乒乓球运动员,他们每个人都有自己的技能值,且各不相等。
现在问你从中选出两个运动员和一个教练组成一场比赛,且要求教练要在两个运动员中间,教练的技能值也要在两个运动员之间。
分析:假设选中A[i]当作教练,则我们需要知道A[0]~A[i-1]有ai个小于A[i],者我只需对前i个插入树状数组中有几个小于A[i]几个,也就是求1~A[i]的前缀和。。同理也可以从右往左再用一遍树状数组,即可得A[i+1]~A[n-1]有bi个大于A[i]。。Si=ai*bi+(i-ai)*(n-i-1-bi),再求S和,我们就可以得到结果。
感觉自己的文字描述语言弱爆了。。。!!!请原谅
// File Name: 1428.cpp // Author: zlbing // Created Time: 2013/3/9 0:33:32 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,n) for(int i=0;i<n;i++) #define REP1(i,n) for(int i=1;i<n+1;i++) const int MAXN=1e5+50; int G[MAXN]; int C[MAXN]; int A[MAXN],B[MAXN]; 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<MAXN){ C[x]+=d; x+=lowbit(x); } } int main(){ int cas; scanf("%d",&cas); while(cas--){ int N; scanf("%d",&N); REP(i,N)scanf("%d",&G[i]); CL(C,0); CL(A,0); CL(B,0); REP(i,N){ A[i]+=sum(G[i]); add(G[i],1); } CL(C,0); for(int i=N-1;i>=0;i--){ B[i]+=N-i-1-sum(G[i]); add(G[i],1); } LL ans=0; REP(i,N) ans+=A[i]*B[i]+(i-A[i])*(N-i-1-B[i]); cout<<ans<<endl; } return 0; }