LA - 4329 - Ping pong

题意:一条街从西到东住着N(3 <= N <= 20000)位乒乓球选手,每位选手有一个属于自己的等级,3个人,2人比赛,1人当裁判,裁判要住在这2个人之间,且裁判的等级也要在这2人之间,问共能举行几场比赛?

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=26&page=show_problem&problem=2330

——>>AC的感觉真是不错!艰辛!!!从2到N-1依次选i为裁判,求其左边有几人比裁判的等级低,记为c[i],再求右边有几人比裁判等级低,记为d[i],比赛场数为c[i]*(N-i-d[i]) + (i-1-c[i])*d[i],当然啦,求c[i]、d[i]时不可一个一个地循环扫,否则TLE。设等级存在数组a[]里,设等级标记存在数组x[],当扫到i当裁判时,该裁判的等级为a[i],等级比他低的等级有a[i]-1, a[i]-2, ...于是扫描等级数组x[],若x[j] == 1,说明等级为j的选手已存在,将前a[i]-1个x[]加起来,就是c[i],从后往前扫就可得d[i],此过程通过树状数组即二叉索引树BIT实现。要注意:c[i]*(N-i-d[i]) + (i-1-c[i])*d[i]可能大于2147483647,所以此处应用64位整数来存。

#include <iostream>
#include <string.h>

using namespace std;

const int maxn = 20000 + 10;        //人数3 <= N <= 20000
const int maxnn = 100000 + 10;      //等级 [1, 100000]
int a[maxn], c[maxn], d[maxn], x[maxnn], BIT[maxnn], N;     //a[i]为i的等级,c[i]为第i个人的西边等级比他低的人数,d[i]为第i个人的东边等级比他低的人数,x[i]为目前为止等级为i的人是否存在,BIT[i]为二叉索引树第i个条的长度

int lowbit(int i)       //数i的二进制表示的从右边开始第一个1对应的值
{
    return i&-i;
}
int sum(int i)      //BIT求x的前i项和
{
    int ret = 0;
    while(i > 0)
    {
        ret += BIT[i];
        i -= lowbit(i);
    }
    return ret;
}
void add(int i, int d)      //当修改x[i]的时候,对应修改二叉索引树中BIT数组
{
    while(i <= maxnn-1)      //注意:这个maxnn-1千万别写成N,需要 >= 100000 因为这是对等级来说的,不是对选手来说的!
    {
        BIT[i] += d;
        i += lowbit(i);
    }
}
int main()
{
    int T, i;
    cin>>T;
    while(T--)
    {
        memset(x, 0, sizeof(x));        //初始化x为0
        memset(BIT, 0, sizeof(BIT));        //初始化BIT为0,因为x数组为0,无论多少个0相加还是0
        cin>>N;
        for(i = 1; i <= N; i++)
            cin>>a[i];
        for(i = 1; i <= N; i++)     //从西往东求第i个人的西边有几个比他等级低的选手,即c[i]
        {
            c[i] = sum(a[i]-1);     //求和
            x[a[i]] = 1;        //标记这个等级已存在
            add(a[i], 1);      //加到BIT去
        }
        memset(x, 0, sizeof(x));        //再次初始化不可少!
        memset(BIT, 0, sizeof(BIT));        //再次初始化不可少!
        for(i = N; i >= 1; i--)     //从东往西求第i个人的东边有几个比他等级低的选手,即d[i]
        {
            d[i] = sum(a[i]-1);     //求和
            x[a[i]] = 1;        //标记这个等级已存在
            add(a[i], 1);      //加到BIT去

        }
        long long sum = 0;      //小心溢出呀!!!
        for(i = 2; i <= N-1; i++)
            sum += c[i]*(N-i-d[i]) + (i-1-c[i])*d[i];       //乘法原理与加法原理
        cout<<sum<<endl;
    }
    return 0;
}

重写:发现之前写的用了一个没有用到的x[]数组~再有,这次用printf输出64位整数,一不留意这是LA,用了%I64d错了一次,悲壮~

#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 20000 + 10;
const int maxv = 100000 + 10;
int a[maxn], c[maxn], d[maxn], BIT[maxv];

int lowerbit(int x)
{
    return x&-x;
}
int sum(int i)
{
    int ret = 0;
    while(i > 0)
    {
        ret += BIT[i];
        i -= lowerbit(i);
    }
    return ret;
}
void add(int i, int x)
{
    while(i < maxv)
    {
        BIT[i] += x;
        i += lowerbit(i);
    }
}

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

        memset(BIT, 0, sizeof(BIT));
        for(i = 1; i <= N-1; i++)
        {
            c[i] = sum(a[i]-1);
            add(a[i], 1);
        }
        memset(BIT, 0, sizeof(BIT));
        for(i = N; i >= 2; i--)
        {
            d[i] = sum(a[i]-1);
            add(a[i], 1);
        }
        long long ret = 0;
        for(i = 2; i <= N-1; i++) ret += c[i]*(N-i-d[i]) + d[i]*(i-1-c[i]);
        printf("%lld\n", ret);
    }
    return 0;
}



转载于:https://www.cnblogs.com/xiaodanding/archive/2013/01/05/3266906.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值