zoukankan      html  css  js  c++  java
  • 问题 F: 对战 II

    题目描述
    在⼀条街道上有n个⼈,他们都喜欢打乒乓球。任意两个⼈的家的位置都不相同,按顺序标为1,2,…,n。每个⼈都有⼀定的⽔平,用两两不等的整数表示。
    当两个⼈想打球的时候,会找另⼀个⼈作为裁判,并到裁判家里进⾏⼀场较量。出于某种原因,他们希望裁判的⽔平介于两⼈之间;同时,他们希望两个⼈到裁判家的总路程不超过两个⼈的家的距离。
    对于两场较量,如果打球的两个⼈不完全相同或者裁判不同,我们就认为这两场较量不同。求不同的较量的总数。

    输入
    输⼊包含多组数据
    输⼊的第⼀⾏是⼀个整数T,表示数据组数;
    每组数据占⼀⾏,包含n+1个整数:n,a1,a2,···,an。其中a1,a2,···,an表示家位于相应位置的⼈的⽔平。

    输出
    对每组数据,用⼀⾏输出⼀个整数,表示不同的较量的总数。

    样例输入
    复制样例数据
    1
    3 1 2 3
    样例输出
    1

    提示
    对于40%的数据,有n≤1000;
    对于所有数据,有T≤20,3≤n≤100000,每个⼈的⽔平都是不超过200000的正整数。

    题解:题目要求满足ai < aj < ak || ai > aj > ak ,其中i
    < j < k , 满足这两个条件的个数有多少, 我们来枚举中间的j,判断左面小于(大于)它 , 右边大于(小于)它的个数, 然后相乘, 解这种题目, 类似于用树状数组求解逆序对, 不过这个数据范围好像有点小, 不需要进行离散化就可以了,先将左边小于a[i] 的个数存储到l[i] 中 , 直接插入a[i],同理将右边大于a[i]的存储到r[i] , 插入a[i] , 不过在处理大于a[i] 的过程中,我们用反向的,最后枚举(2 , n -1) 作为中间点, 然后进行 判断左面小于(大于)它 , 右边大于(小于)它的个数, 然后相乘 , 即l[i] * (n - i - r[i]) + r[i] * (i - 1 - l[i]) ,
    // (n-i-r[i]) 表示右边比 i 大的
    // (i-l[i]-1) 表示左边比 i 大的

    #include <iostream>
    #include <cstring>
    using namespace std;
    const int N = 2e5 + 10 ;
    typedef long long ll ;
    ll a[N] , c[N] , l[N] , r[N] ;
    ll lowbit(int x)
    {
    	return x & -x ;
    }
    ll ask(int x)
    {
        ll ans = 0 ;
    	for( ;x > 0 ; x -= lowbit(x))
    	 ans += c[x];
    	return ans ;
    }
    ll n ;
    void add(int x , int y)
    {
    	for( ; x < N ; x += lowbit(x))
    	 c[x] += y ;
    }
    int main()
    {
        int t ;
        cin >> t ;
    	while(t --)
    	{
    		memset(c , 0 , sizeof c) ;
    		cin >> n ; 
    		memset(l , 0 , sizeof l) ;
    		memset(r , 0 , sizeof r) ;
    		for(int i = 1 ;i <= n ;i ++) cin >> a[i] ;
    		for(int i = 1 ;i <= n ;i ++)
    		 {
    		 	l[i] = ask(a[i] - 1) ;
    		 	add(a[i] , 1) ;
    		 }
    		 memset(c , 0 , sizeof c) ;
    		 for(int i = n ;i >= 1 ;i --)
    		  {
    		  	r[i] = ask(a[i] - 1) ;
    		  	add(a[i] , 1) ;
    		  }
    		  ll ans = 0 ;
    		  for(int i = 2 ;i <= n - 1 ;i ++)
    		   ans += l[i] * (n - i - r[i]) + r[i] * (i - 1 - l[i]) ;
    	      cout << ans << endl ;
    	}
    	return 0 ;
    } 
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    js总结:增加和减少文本框
    java总结:字符串切割
    Spring-----ioc
    Hibernate之二级缓存
    Hibernate之HQL
    Hibernate关联关系(一对多自关联 ,多对多)
    Hibernate关联关系(一对多)
    Hibernate之主键生成策略
    如何使用hibernate完成CRUD操作
    Struts2-----文件上传与拦截器原理
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870889.html
Copyright © 2011-2022 走看看