uva 1428

题意:给出n个乒乓球选手的能力值a[i],要求从其中选出三个人,一个为裁判,两个作为选手,且裁判的能力位于两者之间,位置也位于两者之间,问有多少种方法,类似这样的题,要抽象成数学模型那就应该确定其中一个的位置来找其他两个的数学关系,不妨我们先确定裁判的位置,假设裁判位置为i,那么就得从1~i-1和i+1~n中选两个能力值分别位于裁判两边的选手,那么在1~i-1中假设有c[i](i表示裁判位置)个选手能力低于裁判,那么就应该有(i-1-c[i])个能力高于裁判,而另一边也是如此以数组d[i]记,最后就是变成一个组合问题,答案就是c[i]*(n-i-d[i])+d[i]*(i-1-c[i]);那么后面只需要确定c[i]与d[i]就好,例如c[i]表示的是1-i-1选手中能力值小于裁判a[i]的有哪些,那么正如训练指南里面所说,可以用x[j]来表示能力值为j的人是否存在想x[j]=1代表存在,x[j]=0代表不存在,那么每次计算ai-1以下的能力值所有存在者的个数就行,每次就变成修改某个点的值并统计前缀和的问题,这样便可以使用树状数组来解决,数学模型也就抽象出来了,修改区间点,然后更新算前缀和。

#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<algorithm>

using namespace std;

const int maxn=20005;
int c[maxn],d[maxn],a[maxn];

int lowbit(int x){ return x&(-x); }//按位与求lowbit位 

struct  bittree{
     int size;
     vector<int> C;   
     void clear(){ fill(C.begin(),C.end(),0); }
     int sum(int x){//标准树状数组的求和函数 
         int ret=0;
         while(x>0){
           ret+=C[x];
           x-=lowbit(x);
         }
         return ret;
     }
     
     void add(int x,int d){//标准树状数组的改变单个节点值的操作 
         while(x<=size){
            C[x]+=d;
            x+=lowbit(x);
         }
     }
};

bittree tree;

int main(){
    int t,n;
    scanf("%d",&t);
    while(t--){
         scanf("%d",&n);
         int maxsize=0;
         for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            maxsize=max(maxsize,a[i]);
         }
         tree.C.resize(maxsize);//如果要像数组一样使用的话得先把空间声请了,要不然只能挨个压入容器 
         tree.size=maxsize;
         tree.clear();
         for(int i=0;i<n;i++){
             tree.add(a[i],1);
             c[i]=tree.sum(a[i]-1);
         }
         
         tree.clear();
         for(int i=n-1;i>=0;i--){
             tree.add(a[i],1);
             d[i]=tree.sum(a[i]-1);
         }
         long long ans=0;
         for(int i=0;i<n;i++)ans+=(long long)c[i]*(n-d[i]-i-1)+(long long)d[i]*(i+1-c[i]-1);
         printf("%lld\n",ans);
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值