• ACM学习历程—51NOD 1685 第K大区间2(二分 && 树状数组 && 中位数)


    http://www.51nod.com/contest/problem.html#!problemId=1685

    这是这次BSG白山极客挑战赛E题。

    这题可以二分答案t

    关键在于,对于一个t,如何判断它是否能成为第k大。

    将序列中大于t的置为1,小于t的置为-1,等于t的置为0。那么区间中位数大于t的和就大于0,小于t的就小于0。于是就是判断区间和大于0的个数是否小于等于k

    维护前缀和sum(i),然后统计之前sum(j)小于sum(i)的有多少个,就是以i为右值的区间和大于0的个数。于是就可以用树状数组维护了。

    由于是奇数长度区间,所以树状数组需要维护奇偶长度的前缀和个数。需要特判sum(i) > 0的情况。

     

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <vector>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    //线段树
    //区间每点增值,求区间和
    const int maxN = 100010;
    
    LL d[2][maxN*2];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int t, int id,int pls)
    {
        while(id <= maxN<<1)//id最大是maxN
        {
            d[t][id] += pls;
            id += lowbit(id);
        }
    }
    
    LL sum(int t, int to)
    {
        LL s = 0;
        while(to > 0)
        {
            s = s + d[t][to];
            to -= lowbit(to);
        }
        return s;
    }
    
    LL query(int t, int from, int to)
    {
        return sum(t, to) - sum(t, from-1);
    }
    
    int n, a[maxN], b[maxN];
    LL k;
    
    LL judge(int t)
    {
        for (int i = 0; i < n; ++i)
        {
            if (a[i] > t) b[i] = 1;
            else if (a[i] == t) b[i] = 0;
            else b[i] = -1;
        }
        memset(d, 0, sizeof(d));
        int sum = 0;
        LL ans = 0;
        for (int i = 0; i < n; ++i)
        {
            sum += b[i];
            ans += query(!(i%2), 100005-n, 100005+sum-1);
            if (i%2 == 0 && sum > 0) ans++;
            add(i%2, 100005+sum, 1);
        }
        return ans;
    }
    
    void work()
    {
        int lt, rt, mid;
        lt = rt = a[0];
        for (int i = 1; i < n; ++i)
        {
            lt = min(lt, a[i]);
            rt = max(rt, a[i]);
        }
        while ((LL)lt+1 < rt)
        {
            mid = ((LL)lt+rt)>>1;
            if (judge(mid) > k-1) lt = mid;
            else rt = mid;
        }
        if (judge(lt) <= k-1) printf("%d
    ", lt);
        else printf("%d
    ", rt);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        while (scanf("%d", &n) != EOF)
        {
            cin >> k;
            for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    软件工程实验二
    软件工程实验一
    软件工程作业--ATM自助银行服务系统
    软件工程作业—举例分析流程图与活动图的区别与联系
    第一个随笔
    机器学习 实验四 决策树算法及应用
    机器学习实验三 朴素贝叶斯算法及应用
    机器学习 实验二 K-近邻算法及应用
    飞机订票系统(文档)
    机器学习 实验一 感知器及其应用
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5523820.html
Copyright © 2020-2023  润新知