51nod-1686 第K大区间(二分+尺取法)

Posted LittlePointer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod-1686 第K大区间(二分+尺取法)相关的知识,希望对你有一定的参考价值。

题目链接:

第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]的数,注意相等的;
再二分答案t,check区间众数大于等于t的区间有多少个;(可以设区间众数大于等于t的区间为合法区间)
check的时候采用尺取法,按顺序枚举每个区间的左端点i,然后找到区间右端点的最小值;以这个左端点为合法区间的方案数为n-(r-1);
复杂度为O(nlogn)

AC代码:

//#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <queue>
#include <cmath>
#include <map>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;
#define Riep(n) for(int i=1;i<=n;i++)
#define Riop(n) for(int i=0;i<n;i++)
#define Rjep(n) for(int j=1;j<=n;j++)
#define Rjop(n) for(int j=0;j<n;j++)
#define mst(ss,b) memset(ss,b,sizeof(ss));
typedef long long LL;
template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<0||CH>9;F= CH==-,CH=getchar());
    for(num=0;CH>=0&&CH<=9;num=num*10+CH-0,CH=getchar());
    F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
    if(!p) { puts("0"); return; }
    while(p) stk[++ tp] = p%10, p/=10;
    while(tp) putchar(stk[tp--] + 0);
    putchar(\n);
}

const LL mod=1e9+7;
const double PI=acos(-1.0);
const LL inf=1e10;
const int N=1e5+15;

int n,k;
int a[N],flag[N];
struct node
{
    int a,id,ans;
}po[N];
int cmp(node x,node y)
{
    if(x.a==y.a)return x.id<y.id;
    return x.a<y.a;
}
int cmp1(node x,node y)
{
    return x.id<y.id;
}

int check(int x)
{
    mst(flag,0);
    LL ans=0;
    int num=0;
    int r=0;
    Riep(n)
    {
        while(1)
        {
            int pos=po[r].ans;
          if(pos!=-1) if(flag[pos]>=x||r>n)break;
            r++;
            pos=po[r].ans;
            flag[pos]++;
        }
        ans=ans+n-(r-1);
        flag[po[i].ans]--;
    }
    if(ans>=k)return 1;
    return 0;
}

int main()
{
    read(n);read(k);
    Riep(n)read(po[i].a),po[i].id=i;
    sort(po+1,po+n+1,cmp);
    po[0].ans=po[0].a=-1;
    Riep(n)
    {
        if(po[i].a!=po[i-1].a)po[i].ans=i;
        else po[i].ans=po[i-1].ans;
    }
    sort(po+1,po+n+1,cmp1);

    int l=1,r=n;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))l=mid+1;
        else r=mid-1;
    }
    print(l-1);
    return 0;
}

 

以上是关于51nod-1686 第K大区间(二分+尺取法)的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1686 第k大区间

尺取法二分河南省第十三届ICPC大学生程序设计竞赛 C题

hihocoder-1483区间价值 (二分+尺取法)

USACO35 翻转奶牛(尺取法)

luogu 1712 区间(线段树+尺取法)

51nod 1674 区间的价值V2(思维+拆位+尺取法)