51NOD 1686 第K大区间 二分

第k大区间
 

定义一个区间的值为其众数出现的次数
现给出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


题解:
  二分答案,
  我们假设x,计算出多少个区间的众数大于等于K就好了
  方法就是:枚举一个区间的右端点,那么我们假设找到一个左端点尽量大,那么就是固定的右端点的答案,累加就是了
  注意这题不要用map等STL,会超时
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include<vector>
using namespace std;
const int N = 1e5+10, M = 30005, mod = 1e9+7, inf = 0x3f3f3f3f;
typedef long long ll;
//不同为1,相同为0
void read(ll &x){
    char ch=getchar();x=0;
    for (;ch<'0';ch=getchar());
    for (;ch>='0';ch=getchar()) x=x*10+ch-'0';
}
vector<int> G[N];
int H[N];
ll n,k,a[N],pos[N],b[N];
ll cal(int x) {
    if(x==1) return n*(n-1)/2;
    ll ans = 0,L = 0;
    for(int i=1;i<=n;i++) G[i].clear();
    memset(H,0,sizeof(H));
    for(int i=1;i<=n;i++) {
        if(H[a[i]]>=x-1) {
            pos[i] = G[a[i]][H[a[i]]+1 - x];
        }
        else pos[i] = 0;
        L = max(L,pos[i]);
        ans+=L;
        H[a[i]]++;
        int tmp = H[a[i]];
        G[a[i]].push_back(i);
    }
   // cout<<pos[n]<<endl;
    //cout<<ans<<endl;
    return ans;
}
int main() {
    read(n),read(k);
    for(int i=1;i<=n;i++) read(a[i]), b[i] = a[i];
    sort(b+1,b+n+1);
    int c = unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) a[i] = lower_bound(b+1,b+c+1,a[i]) - b;

   // cout<<cal(2)<<endl;
   int l = 1, r = n;
    ll  ans = 1;
    while(l<=r) {
        int mid = (l+r)>>1;
         if(cal(mid)>=k) l = mid+1, ans = mid;
         else r = mid-1;
    }
    printf("%lld
",ans);
    //cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/zxhl/p/5338600.html