zoukankan      html  css  js  c++  java
  • UVA1428 Ping pong(树状数组)

    题目链接

    题意:

    n个人,从左到右排列,每个人都有一个不同的技能值 ai, 每场比赛3个人: 两名选手, 一名裁判。 裁判必须在两名选手中间, 并且技能值也在两名选手之间, 问一共能组织多少种比赛。

    分析:

      考虑第i个人当裁判的情形。假设 ai 到 ai-1 中有 ci 个比 ai 个小, 那么就有 (i-1)-ci 个比 ai 大; 同理, 假设 ai+1 到 an 中有di个比ai 小, 那么就有 (n-i)-di 个比 ai 大。 根据乘法原理和加法原理, i当裁判 有 ci(n-i-di)+(i-ci-1)*di 种比赛。 这样问题转化为求 ci 和 di.

      题目已经明确每个人都有一个不同的技能值。 那么要求 ci , 先将树状数组 x 清空, 从左到右扫描 ai , 每运行一次 add(ai, 1), 就运行一次 sum(ai-1), sum求的是比 ai 小的数的个数, 因为是依次添加, 求 ai 时, ai 右边的数是没有加入树状数组 x 的, 这样 sum(ai-1), 求的就是 在 i 左边的比 ai 小的数的个数, 即 ci。 同理可以计算出 di

    注意:

    有一个调试了4个多小时的BUG(欲哭无泪啊), 那就是 数组 x 的大小并不是 n , 因为 n 代表人的个数,而 x 存的值为技能值,  即 x 的大小为 a1~an 最大的技能值。

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 100000 + 10;
    
    int c[20000+10], d[20000+10], x[maxn], a[20000+10], n, mn;
    
    int lowbit(int e) { return e & (-e); }
    
    void add(int p, int ad){
        while(p<=mn){   //这里是 mn, 并非 n
            x[p] += ad;
            p += lowbit(p);
        }
    }
    
    int sum(int p){
        int ret = 0;
        while(p > 0){
            ret += x[p];
            p -= lowbit(p);
        }
        return ret;
    }
    
    int main(){
        int T;
        scanf("%d", &T);
        while(T--){
            mn = 0;
    
            scanf("%d", &n);
    
            for(int i=1; i<=n; i++){
                scanf("%d", &a[i]);
                mn = max(mn, a[i]);
            }
    
            memset(x, 0, sizeof(x));
            for(int i=1; i<=n; i++){
                add(a[i], 1);
                c[i] = sum(a[i]-1);
            }
    
            memset(x, 0, sizeof(x));
            for(int i=n; i>=1; i--){
                add(a[i], 1);
                d[i] = sum(a[i]-1);
            }
    
            long long int ans = 0;
            for(int i=1; i<=n; i++){
                ans += (long long)c[i]*(n-i-d[i]) + (long long)(i-c[i]-1)*d[i];
            }
    
            printf("%lld\n", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    Ubuntu18.04 一些好用的扩展
    Java并发编程:volatile关键字解析
    SpringCloud(0) 外行人都能看懂的SpringCloud,错过了血亏!
    Java8中的流操作-基本使用&性能测试
    JDBC基本操作
    单例模式(二)
    单例模式(一)static、final和单例模式
    Lombok的使用与原理
    Linux下出现permission denied的解决办法
    虚拟机安装
  • 原文地址:https://www.cnblogs.com/tanhehe/p/3065536.html
Copyright © 2011-2022 走看看