您的位置:首页 > 其它

LA4329乒乓比赛_树状数组

2016-01-11 21:05 302 查看
题目大意:
一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术。每个人都有一个能力值a[i]。每场比赛需要三个人:两名选手,一名裁判。他们有个奇怪的约定,裁判必须住在两名选手之间,而裁判的能力值也必须在两名选手之间。问一共能组织多少种比赛。

分析:
考虑第i个人,假设a1到ai-1中有ci个比ai小,那么就有(i-1)-ci个比ai大;同理,如果ai+1到an中有di个比ai小,那么就有(n-i)-di个比ai大。更具乘法原理和加法原理,i当裁判就有
ci * (n-i-di) + (i-1-ci)*di
种比赛。(感觉这种思路简直碉堡了)

然后问题就转化为了计算数组c和数组d。这样的话就很容易想到使用树状数组去计算前缀和。

比如输入一个数组,

PS:树状数组的运用主要目的是快速的累加和和修改值,所以这里使用了一个长度为100010的数组C,初始化为0,

如果我们输入  14 3 7 15 1 这样的话,第一次输入了14,所以C[14]+=1,变成1,然后从下面往上开始自增,在算cc[0]时候,传递过去num[i],然后使用加法模板来相加,这样结果就是14左边的小于14的值,dd也是一样的思路,注意dd的计算和cc的计算是相反的,从后往前加(可以想想为什么,注意树状数组相加时候只能从后往前累加!)。

代码如下

#include <iostream>
#include <algorithm>
using namespace std;
#define MAXSIZE 100010
int num[MAXSIZE];
int C[MAXSIZE];//树状数组的段和
int cc[MAXSIZE];//cc[i]表示前面有多少元素比它小
int dd[MAXSIZE];//dd[i]表示后面有多少元素比它大
int n;//n代表输入元素的个数
#define LOWBITE(x) (x&(-x))
void add(int num,int increse)
{

while(num<MAXSIZE)
{
C[num]+=increse;
num+=LOWBITE(num);
}
}
int sum(int num)
{
int ret=0;
while(num>0)
{
ret+=C[num];
num-=LOWBITE(num);
}
return ret;

}
int main()
{
int T;
int i;
int ans;
cin>>T;
while(T--)
{
cin>>n;
ans=0;
for( i=0;i<n;i++)
{
cin>>num[i];
}
memset(C,0,sizeof(C));
memset(cc,0,sizeof(cc));
for(i=0;i<n;i++)
{
add(num[i],1);
cc[i]=sum(num[i]-1);
}
memset(C,0,sizeof(C));
for(i=n-1;i>=0;i--)
{
add(num[i],1);
dd[i]=sum(num[i]-1);

}
for(i=1;i<n;i++)
{
ans+=cc[i]*(n-i-1-dd[i])+(i-cc[i])*dd[i];
}
cout<<ans<<endl;

}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: