51nod 1686 第K大区间

一、题意

  这题刚看到想了5分钟左右没有啥思路(在上某大佬的某节课发现并不能听懂也似乎没啥实践指导意义,遂怒写一题)。于是查了下看看对方的代码,正准备进行:看到半懂,复刻,重写若干遍这种流程的时候,发现其思路意外的简单。

  题意复制如下:
定义一个区间的值为其众数出现的次数
现给出n个数,求将所有区间的值排序后,第K大的值为多少。
第一行两个数n和k(1<=n<=100000,k<=n*(n-1)/2) 
第二行n个数,0<=每个数<2^31

二、题解

  用尺取法统计大于某个值得区间的个数,之后可以在ON的时间内搞定检查,因为必然具有单调性,于是可以进行二分。

三、代码

#include<bits/stdc++.h>
using namespace std;

#define ll long long 
#define veci vector<int>
const ll MAXN=100233;


ll arr[MAXN];
ll numbers[MAXN];
ll n,k;
int vis[MAXN];
inline int checkPos(int i)
{
    return lower_bound(numbers,numbers+n,arr[i])-numbers;
}
ll check(int limit)
{
    ll ans=0;
    memset(vis,0,sizeof(vis));
    int spos=-1;
    for(int i=0;i<n;++i)
    {
        vis[arr[i]]++;
        while(vis[arr[i]]>=limit)
        {
            ans+=n-i;
            spos++;
            vis[arr[spos]]--;
        }
    }return ans;
}
int search(int a,int b)
{
    if(a==b-1)return a;
    int mid=(a+b)/2;
    if(check(mid)<k)search(a,mid);
    else search(mid,b);
}
void init()
{
    for(int i=0;i<n;++i)
    {
        cin>>arr[i];
        numbers[i]=arr[i];
    }sort(numbers,numbers+n);
    for(int i=0;i<n;++i)
    {
        arr[i]=checkPos(i);
    }
    cout<<search(1,n);
    
}

int main()
{
    cin.sync_with_stdio(false);
    cin>>n>>k;init();
    
    
    return 0;
}
原文地址:https://www.cnblogs.com/rikka/p/7879604.html