51nod 1686 第K大区间【离散化+二分】

题目链接:

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1686

题意:

定义一个区间的值为其众数出现的次数。
现给出n个数,求将所有区间的值排序后,第K大的值为多少。

分析:

二分答案,对于每个值判断大于等于该值的区间个数是否大于等于K
判断某个值mid时枚举右端点,找到使得以该右端点为众数的最大的左端点。那么该区间就是满足题意的一个最小的区间之一,再加上前面的区间外的元素,就可以得到右端点为该点的满足条件的区间数。这样保证了任何被加进去的区间中的众数至少为mid。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn], b[maxn];
int cnt[maxn];
int n;
long long k;

bool judge(int mid)
{
    long long ans = 0;
    int  l = 1;
    bool flg = false;
    memset(cnt, 0,  sizeof(cnt));
    for(int i = 1; i <= n; i++){
        cnt[a[i]]++;
        if(cnt[a[i]] >= mid){
            flg = true;
            if(cnt[a[i]] > mid){
                l++;
                cnt[a[i]]--;
            }
            while(a[l] != a[i]){
                l++;
                cnt[a[l]]--;
            }
        }
        if(flg)  ans += l;
    }
    return ans >= k;
}
int main (void)
{
    cin>>n>>k;
    int maxx = 0;
    for(int i = 1 ;i <= n; i++){
            cin>>a[i];
            b[i] = a[i];
    }
    sort(b + 1, b +1 + n);
    int t = unique(b + 1, b + n + 1) - (b + 1);
    for(int i = 1; i <= n; i++){
        a[i] = lower_bound(b + 1, b + t + 1, a[i]) - (b + 1);
    }
    int l = 1, r = n + 1;
    while(l + 1 < r){
        int mid = l + r>>1;
        if(judge(mid)) l = mid;
        else r =mid;
    }
    cout<<l<<endl;
    return 0;
}
posted @ 2016-04-26 10:23  zhuyujiang  阅读(108)  评论(0编辑  收藏  举报