题目链接 https://vjudge.net/problem/UVALive-4329
【题意】
一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术,每个人都有一个不同的技能值a[i],每次比赛需要三个人,两名选手和一名裁判。他们有一个奇怪的规定,即裁判必须住在两名选手之间,且技能值也必须在两名选手之间。问你一共能组织多少次比赛?
【思路】
考虑第i个人当裁判,设a(1)~a(i-1)这i-1个人中有c[i]个人比a[i]小,则有i-1-c[i]个比a[i]大。同理设a(i+1)~a(n)这n-i个人中有d[i]个比a[i]小,则有n-i-d[i]个比a[i]大。根据加法乘法原理,i当裁判时可以举办c[i]×(n-i-d[i])+d[i]×(i-1-c[i])场比赛,总的答案就是对每个裁判举办的比赛次数求和即可。(总觉得按照大白这样计数有点问题,我觉得应该考虑每个元素小于,大于和等于a[i]才对,但是直接A了,就没有多想)要用到BIT来求解c[i]和d[i],可以在O(nlogn)的时间预处理出c,d数组,方法和求逆序对类似。
#include
using namespace std;
typedef long long ll;
const int maxn=20005;
const int maxa=100005;
int n;
int a[maxn];
int c[maxn],d[maxn];
int bit[maxa],len;
int sum(int i){
int ans=0;
while(i){
ans+=bit[i];
i-=i&-i;
}
return ans;
}
void add(int i,int x){
while(i<=len){
bit[i]+=x;
i+=i&-i;
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
len=0;
scanf("%d",&n);
for(int i=1;i<=n;++i) {
scanf("%d",&a[i]);
len=max(len,a[i]);
}
memset(bit,0,sizeof(bit));
for(int i=1;i<=n;++i){
c[i]=sum(a[i]-1);
add(a[i],1);
}
memset(bit,0,sizeof(bit));
for(int i=n;i>=1;--i){
d[i]=sum(a[i]-1);
add(a[i],1);
}
ll ans=0;
for(int i=1;i<=n;++i){
ans+=(ll)c[i]*(ll)(n-i-d[i])+(ll)d[i]*(ll)(i-1-c[i]);
}
printf("%lld\n",ans);
}
return 0;
}