zoukankan      html  css  js  c++  java
  • AtCoder ARC 101 D Median of Medians(逆序对)

    题意:
    给一个数组,取每一段区间的中位数重新构成一个一个数组,求出该数组的中位数
    中位数是指序列中A的第$frac{|A|}{2}+1$个元素
    分析:
    刚读完题感觉此题很神,做完之后发现确实很神,不得不赞叹Atcoder出题人太强了。。。
    考虑二分答案。
    我们二分最后的中位数是mid,把原序列大于mid的数变成1,小于等于的是-1
    之后处理出前缀和sum
    然后发现一个重要的性质:只要一段区间的和大于0,那么这段区间的中位数就一定大于等于mid
    于是要求的答案就转化成了当前序列中的顺序对($i < j && a[i] < a[j]$)个数。
    大家肯定知道逆序对的求法可以通过树状数组和归并排序解决,那么顺序对也一样的,笔者用的是树状数组去求。
    如果算出来的顺序对个数$>n*(n-1)/4$就是$return true$(n*(n-1)个区间的中间是要在/2)
    于是问题就被完美解决了
    代码:

    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <bitset>
    #include <cstdio>
    #include <cctype>
    #include <string>
    #include <cstring>
    #include <cassert>
    #include <climits>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std ;
    
    #define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
    #define Rep(i, a, b) for (int (i) = (a) - 1; (i) < (b); (i)++)
    #define REP(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
    #define clr(a) memset(a, 0, sizeof(a))
    #define Sort(a, len, cmp) sort(a + 1, a + len + 1, cmp)
    #define ass(a, sum) memset(a, sum, sizeof(a))
    
    #define ls ((rt) << 1)
    #define rs ((rt) << 1 | 1)
    #define lowbit(x) (x & -x)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define endl '
    '
    #define ENDL cout << endl
    #define SZ(x) ((int)x.size())
    
    typedef long long ll ;
    typedef unsigned long long ull ;
    typedef vector <int> vi ;
    typedef pair <int, int> pii ;
    typedef pair <ll, ll> pll ;
    typedef map <int, int> mii ;
    typedef map <string, int> msi ;
    typedef map <ll, ll> mll ;
    
    const int N = 100010 ;
    const double eps = 1e-8 ;
    const int iinf = INT_MAX ;
    const ll linf = 2e18 ;
    const double dinf = 1e30 ;
    const int MOD = 1000000007 ;
    
    inline int read(){
        int X = 0, w = 0 ;
        char ch = 0 ;
        while (!isdigit(ch)) { w |= ch == '-' ; ch = getchar() ; }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar() ;
        return w ? - X : X ;
    }
    
    void write(int x){
         if (x < 0) putchar('-'), x = - x ;
         if (x > 9) write(x / 10) ;
         putchar(x % 10 + '0') ;
    }
    
    void print(int x) {
        cout << x << endl ;
        exit(0) ;
    }
    
    void PRINT(string x) {
        cout << x << endl ;
        exit(0) ;
    }
    
    void douout(double x){
         printf("%lf
    ", x + 0.0000000001) ;
    }
    
    int a[N], sum[N * 10], bit[N * 10] ;
    int n, l, r ;
    
    void add(int a) {
        for (; a <= 2 * N; a += lowbit(a)) bit[a]++ ;
    }
    
    int query(int a){
        int res = 0 ;
        for (; a; a -= lowbit(a)) res += bit[a] ;
        return res ;
    }
    
    int check(int x) {
        for (int i = 0; i <= 2 * N; i++) bit[i] = 0 ;
        clr(sum) ;
        for (int i = 1; i <= n; i++) {
            sum[i] = sum[i - 1] + (a[i] >= x ? 1 : -1) ;
        }
        ll ans = 0 ;
        for (int i = 0; i <= n; i++) {
            ans += query(sum[i] + N) ;
            add(sum[i] + N) ;
        }
        return ans >= 1ll * n * (n + 1) / 4 ;
    }
    
    signed main(){
        scanf("%d", &n) ;
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]), r = max(r, a[i]) ;
        while (l <= r) {
            int mid = (l + r) >> 1 ;
            if (check(mid)) l = mid + 1 ;
            else r = mid - 1 ;
        }
        printf("%d
    ", r) ;
    }
    
    /*
    写代码时请注意:
        1.是否要开Long Long?数组边界处理好了么?
        2.实数精度有没有处理?
        3.特殊情况处理好了么?
        4.做一些总比不做好。
    思考提醒:
        1.最大值和最小值问题可不可以用二分答案?
        2.有没有贪心策略?否则能不能dp?
    */
    AC
    加油ヾ(◍°∇°◍)ノ゙
  • 相关阅读:
    BCB 如何让Application收到SendMessage发送来的消息
    用BCB 画 Code128 B模式条码
    遍历SQL SERVER中所有存储过程和触发器
    EXCEL导入数据到SQL SERVER 2008
    TListView控件的ReadOnly属性的一个Bug
    Using Microsoft Visual C++ DLLs with C++Builder
    行列转换的例子
    WCF 使用Stream模式进行文件上传 --节选自Packt.Net.Framework.4.5.Expert.Programming.Cookbook
    WCF Endpoint分类
    SQL Error: 1064, SQLState: 42000
  • 原文地址:https://www.cnblogs.com/harryhqg/p/10054741.html
Copyright © 2011-2022 走看看