您的位置:首页 > 其它

UVALive-4329-Ping-pong

2016-07-15 19:30 302 查看
                                                                                                                                          Ping
pong

Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu 
N (3 ≤ N ≤ 20000) ping pong players live along a west-east street(consider the street as a line segment). 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?

Input 

The first line of the input contains an integer T (1 ≤ T ≤ 20), indicating the number of test cases, followed by T lines each of which describes a test case. 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).

Output

For each test case, output a single line contains an integer, the total number of different games.

Sample Input
1 3 1 2 3
Sample Output
1

题意:

已知n个乒乓球爱好者的能力值,以及输入顺序就是爱好者住所地相对顺序,要求选3个人出来比赛,三个人中有一个人的能力值以及住所地位置要在其他两人中间,求所有的组合方案数量。

题目链接:Ping-pong

解题思路:

把所有人的能力值按顺序存储,这样就先解决了住所问题,接下来只要考虑 1 到 i-1 区间 和 i+1 到 N(N = 1e5)。
假设第i个人前面有b[i]个人能力值比 i 小,那么其余  i - 1 - b[i] 的能力值都比i大;同理,第i个人后面有 d[i]个人能力值比i小,那么其余 n - i - d[i] 的能力值都比 i 大。然后组合一下,总方案数应为 b[i] * (n - i -d[i]) + d[i] * (i - 1 - b[i])。

求b[i] 和 d[i]都是比较能力值的,所以树状数组的范围为能力值的范围N(虽然刚开始以为会超时,不敢写),树状数组c[i]表示能力值为 i 的人出现过,那么 getsum(i - 1) 就为 能力值 1 到 i -1 出现的人数,这个地方需要按序求对应的b[i] ,d[i]值,因为要保证住所的条件。

最后枚举n个人作中间那个人,套用结论即可。

此题关键还是要想清楚该用什么样的树状数组,值得体会!

代码:

//Ping pong
#include
#include
#define N 100005
using namespace std;

typedef long long LL;
int c
,n,a
,b
,d
; //c为树状数组,a为存储输入数据,b[i]存储前面能力值比i小的人数
//d[i]存i后面能力值比i小的人的人数
int lowbit(int t)
{
return t&(-t);
}
void updata(int p,int f) //树状数组更新数组值
{
while(p <= N){
c[p] += f;
p += lowbit(p);
}
}
int getsum(int p)  //树状数组区间求和
{
int s = 0;
while(p > 0) {
s += c[p];
p -= lowbit(p);
}
return s;
}

int main()
{
int i,T;
scanf("%d",&T);
while(T--){
LL ans = 0;
scanf("%d",&n);
for(i = 1;i <= n;i++){
scanf("%d",&a[i]);
}

memset(c,0,sizeof(c));
for(i = 1;i <= n;i++){
b[i] = getsum(a[i] - 1); //住在前面,能力值比a[i] 小的人
updata(a[i],1);          //在树状数组中标记此人已经出现
}
memset(c,0,sizeof(c));
for(i = n;i >= 1;i --){
d[i] = getsum(a[i] - 1); //住在后面,能力值比a[i]小的人
updata(a[i],1);
}
for(i = 1;i <= n;i++){      //枚举每个裁判
ans +=(LL) b[i] * (n - i - d[i]) + d[i] * (i - 1 - b[i]);//前面有b[i]个人能力值比b[i]小,后面有n-i-d[i]个人能力值比i大
////后面有d[i]个人能力值比b[i]小,前面有i-1-b[i]个人能力值比i大
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息