UVALive 4329 - Ping Pong(BIT)

题目链接 https://vjudge.net/problem/UVALive-4329

【题意】
一条大街上住着n个乒乓球爱好者,经常组织比赛切磋技术,每个人都有一个不同的技能值a[i],每次比赛需要三个人,两名选手和一名裁判。他们有一个奇怪的规定,即裁判必须住在两名选手之间,且技能值也必须在两名选手之间。问你一共能组织多少次比赛?

【思路】
考虑第i个人当裁判,设a(1)~a(i-1)这i-1个人中有c[i]个人比a[i]小,则有i-1-c[i]个比a[i]大。同理设a(i+1)~a(n)这n-i个人中有d[i]个比a[i]小,则有n-i-d[i]个比a[i]大。根据加法乘法原理,i当裁判时可以举办c[i]×(n-i-d[i])+d[i]×(i-1-c[i])场比赛,总的答案就是对每个裁判举办的比赛次数求和即可。(总觉得按照大白这样计数有点问题,我觉得应该考虑每个元素小于,大于和等于a[i]才对,但是直接A了,就没有多想)要用到BIT来求解c[i]和d[i],可以在O(nlogn)的时间预处理出c,d数组,方法和求逆序对类似。

#include
using namespace std;
typedef long long ll;

const int maxn=20005;
const int maxa=100005;

int n;
int a[maxn];
int c[maxn],d[maxn];

int bit[maxa],len;

int sum(int i){
    int ans=0;
    while(i){
        ans+=bit[i];
        i-=i&-i;
    }
    return ans;
}

void add(int i,int x){
    while(i<=len){
        bit[i]+=x;
        i+=i&-i;
    }
}

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

        memset(bit,0,sizeof(bit));
        for(int i=1;i<=n;++i){
            c[i]=sum(a[i]-1);               
            add(a[i],1);
        }

        memset(bit,0,sizeof(bit));
        for(int i=n;i>=1;--i){
            d[i]=sum(a[i]-1);
            add(a[i],1);
        }

        ll ans=0;
        for(int i=1;i<=n;++i){
            ans+=(ll)c[i]*(ll)(n-i-d[i])+(ll)d[i]*(ll)(i-1-c[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/wafish/p/10465300.html

你可能感兴趣的:(UVALive 4329 - Ping Pong(BIT))