UVA1428 Ping pong(树状数组)

UVA1428 Ping pong(树状数组)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4174

题意:

        一条大街上住着n个乒乓球爱好者,他们经常组织乒乓球比赛且每个人的能力值ai都不同.每次比赛需要2个比赛者和一个裁判,他们有一个奇怪的规定:当裁判的那个人必须住在这两个比赛者之间,且裁判的能力值也必须在这两个人之间.问一共有多少种比赛组织方式.

        输入:首先是T(1<=T<=20),表示实例个数.对于每个实例第一行是一个n(3<=n<=20000),然后是n个不同的整数即a1,a2…an(1<=ai<=100000),按照他们的住所位置从左到右给出每个人的能力值.

        输出:比赛组织的总数.

分析:

        对于第i个(任意一个)裁判,他能组织多少种比赛呢?

        假设a1到ai-1有S_L[i]个能力值比ai小的,那么有i-1-S_L[i]个能力值比ai大的.同理可得S_R[i]为从i+1到n有B[i]个人能力值比ai小.那么i当裁判能组织的比赛种数是:S_L[i]*(n-i-S_R[i])+(i-1-S_L[i])*S_R[i]种. 我们只需要求出所有裁判的S_L[i]和S_R[i]即可求出所有比赛种数.

        如何求S_L[i]呢(即在a[i]左边且比a[i]值小的数个数)? 我们令X[n]作为标记数组,假设当前我们扫描到了第i个点,此时如果X[y]==1,那么表示第i个点左边出现了一个a[k]==y的值且k<i。那么这时,我们只要用树状数组计算X[n]数组中区间[1, a[i]-1]的和即可(想想是不是)。

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=20000+100;
const int MAX_NUM=100000+100;
int S_L[MAXN],S_R[MAXN];
int x[MAX_NUM];
int c[MAX_NUM];
int a[MAXN];//能力值
int max_a;
int lowbit(int i)
{
    return i&(-i);
}
int sum(int i)//求从A[1]到A[i]的和
{
    int res=0;
    while(i>0)
    {
        res += c[i];
        i-=lowbit(i);
    }
    return res;
}
void add(int i,int d)//使得C数组的所有包含A[i]的项都加上d
{
    while(i<=max_a)//这里max_a 是能力值的上限
    {
        c[i]+=d;
        i += lowbit(i);
    }
}
int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        max_a=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            max_a=max(max_a,a[i]);
        }

        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            S_L[i]=sum(a[i]);
            add(a[i],1);
        }
        memset(c,0,sizeof(c));
        for(int i=n;i>=1;i--)
        {
            S_R[i]=sum(a[i]);
            add(a[i],1);
        }
        long long ans=0;
        for(int i=1;i<=n;i++)
        {
            ans += (long long)S_L[i]*(n-i-S_R[i])+(long long)(i-1-S_L[i])*S_R[i];
        }
        printf("%lld\n",ans);//注意UVA关于64位整数的格式
    }
    return 0;
}


  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值