这道题是真的好
思想很好
思路其实也不是很难
但是也不容易理解
首先,这道题运用了二分
因为答案一定是1~n(区间众数最多n个,最少1个)
那么从1~n二分mid,二分后判断区间值比mid大的区间有几个
如果大于K说明mid取的小了,应该取大一点,反之取小一点,最后找到答案
那么如何判断区间值比mid大的区间有几个
遍历一下所有数,如果有的数的个数等于mid,那么这个区间的右端点往右移的区间的区间值肯定都比它大
然后左边边向右移,如果区间值还不变,那么可以再让 l 往右移,存储一下区间个数
#include<bits/stdc++.h>
using namespace std;
int n;
long long k;
int A[100005];
int B[100005];
int num[100005];
bool check(int x)//区间值为大于等于x的个数
{
memset(num,0,sizeof(num));//num存储的是有几个数
long long res = 0;//res存区间值为大于等于x的个数
int mx = 0;
int s = 1, e = 1;
for(e=1; e<=n; e++)
{
mx = max(mx,++num[A[e]]);//mx表示当前1-e区间内众数的个数
if(mx==x)//如果区间的众数个数为x个
{
while(mx==x)
{
res += n-e+1;//区间右边右移的区间的值都大于等于x
num[A[s]]--;//把区间的第一个数去掉
if(num[A[s]]==mx-1)//如果去掉的是原区间的众数
{
mx--;
}
s++;//指向区间的下一个数
}
}
if(res>=k)//如果区间值大于等于x的个数大于k,说明实际值要比x大
{
return true;
}
}
return false;
}
bool cmp(int a,int b)
{
return A[a]<A[b];
}
int main()
{
while(scanf("%d%I64d",&n,&k)==2)
{
for(int i=1; i<=n; i++)
{
scanf("%d",&A[i]);
B[i]=i;
}
sort(B+1,B+1+n,cmp);//这个操作十分值得学习!
for(int i=1,j=1; i<=n; j++)//初始化操作,离散化操作
{
int kk = i+1;
while(kk<=n&&A[B[kk]]==A[B[i]])
kk++;
while(i<kk)
{
A[B[i++]]=j;
}
}
int s = 1, e = n;
while(s<e)//二分查找
{
int m = (s+e)>>1;
if(m==s)//如果找到底了还没找到
break;
if(check(m))//判断值为m的区间与k的大小,如果为真,应该大的找
{
s = m;
}
else
{
e = m-1;
}
}
if(check(e))//特殊判断一下最后一个点
s=e;
printf("%d\n",s);
}
return 0;
}