51Nod【1686】——1686 第K大区间(尺取+二分)

基准时间限制:1 秒 空间限制:131072 KB

定义一个区间的值为其众数出现的次数。
现给出n个数,求将所有区间的值排序后,第K大的值为多少。
众数(统计学/数学名词)_百度百科

Input

第一行两个数n和k(1<=n<=100000,k<=n*(n-1)/2)
第二行n个数,0<=每个数<2^31

Output

一个数表示答案。

Input示例

4 2
1 2 3 2

Output示例

2

看到一脸懵逼,后来发现看错题了。。。。。,由于值最后价值为[1,n],所以我们可以通过二分,去检查二分出来的值是否正确,大于它的是否为k-1个。检验的时候可以通过尺取的方式。

#include <bits/stdc++.h>
#define fread(x) freopen(x,"r",stdin)
#define fwrite(x) freopen(x,"w",stdout)
using namespace std;
typedef long long LL;
const int Max = 1e6;
LL arr[Max],a[Max];
int Ls[Max];
int n,k;
int num[Max];
bool ok(int s) {
    memset(num,0,sizeof(num));
    LL nu = 0; int L = 1;
    for(int i = 1;i<=n;i++ ){
        num[Ls[i]]++;
        if(num[Ls[i]] > s) {
            while(num[Ls[i]]> s) {
                nu+=(n-i+1);
                num[Ls[L++]]--;
            }
        }
        if(nu >= k) return false;
    }
    return nu<=k;
}
int Solve() {
    int L = 1,R = n,ans =  1;
    while(L<=R) {
        int mid = (L+R)>>1;
        if(ok(mid)) {
            ans = mid;
            R = mid-1;
        }
        else L = mid+1; 
    }
    return ans;
}
int main() {
    scanf("%d %d",&n,&k);
    for(int i =1 ; i<=n;i++) {
        scanf("%lld",&arr[i]);
        a[i] = arr[i];
    }
    sort(arr+1,arr+n+1);
    arr[0] = 1;
    for(int i = 2;i <= n;i++) if(arr[arr[0]] != arr[i]) arr[++arr[0]] = arr[i];
    for(int i = 1;i <= n;i++) Ls[i] = lower_bound(arr+1,arr+arr[0]+1,a[i])-arr;
    printf("%d\n",Solve());
    return 0;
}

你可能感兴趣的:(51Nod【1686】——1686 第K大区间(尺取+二分))