题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2492
Ping pong
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4961 Accepted Submission(s): 1811
Each player has a unique skill rank. To improve their skill rank, they often compete with each other. If two players want to compete, they must choose a referee among other ping pong players and hold the game in the referee's house. For some reason, the contestants can’t choose a referee whose skill rank is higher or lower than both of theirs.
The contestants have to walk to the referee’s house, and because they are lazy, they want to make their total walking distance no more than the distance between their houses. Of course all players live in different houses and the position of their houses are all different. If the referee or any of the two contestants is different, we call two games different. Now is the problem: how many different games can be held in this ping pong street?
Every test case consists of N + 1 integers. The first integer is N, the number of players. Then N distinct integers a1, a2 … aN follow, indicating the skill rank of each player, in the order of west to east. (1 <= ai <= 100000, i = 1 … N).
3 1 2 3
题意:
一条大街上住着n个乒乓球爱好者,经常组织比赛。每个人都有一个技能值ai,每场比赛需要3个人:两名选手和一名裁判。规定裁判位置必须在两个选手的中间,而且技能值也必须在两个选手的中间,问一共能组织多少种比赛 题解:考虑第i个人当裁判的呃情况,求当前某一个位置的前面和后面有多少个数字比这个数字小,思路有点像求逆序对数的题目,这个题来自于刘汝佳大神的树状数组练习题,P197页很详细的分析,这里注意读题,他的题解都是建立在每个人有独特的技术值,即每个数在树状数组中只会出现一次,还要注意,如果数字太大的话要先离散化,但是这个题不离散也可以但是要用long long输出 代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const LL N = ;
LL mp[N];
LL tree[N];
LL lowbit(LL x) {
return x&(-x);
}
LL sum(LL x){
LL ans = ;
while(x>){
ans += tree[x];
x-=lowbit(x);
}
return ans;//记得写返回值
}
int n;
void add(LL x){
while(x<N){
tree[x]++;
x+=lowbit(x);
}
}
void init()
{
for(int i = ; i < N; i++)
tree[i] = ;
}
LL c[N];//当前位置前面有多少人技能值比它小
LL d[N];//当前位置后面有多少人技能值比它小
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = ; i < n; i++)
{
scanf("%lld",&mp[i]);
} LL ans = ;
init();
for(int i = ; i < n ; i++){//枚举所有的位置上的人当裁判的比赛局数
c[i] = sum(mp[i]);add(mp[i]);
}
init();
for(int j = n-; j >=; j--){
d[j] = sum(mp[j]);add(mp[j]);
}
for(int i = ; i < n; i++){
ans = ans + c[i]*(n-i-d[i]-)+(i-c[i])*d[i];
//printf(" c = %lld d = %lld ans = %lld ",c[i], d[i], ans);
}
printf("%lld\n",ans);
}
return ;
}