解析:
套路! 套路! 套路! 一定要谨记!!!!!!!!
(套路)将求 k 大值大于等于 m 转化为求值大于等于 m 的数的数量大于等于 k。
套路二分枚举答案t。二分check的条件就是判断有多少个区间的众数>t
对于check的判断我详细说明一下(利用双指针) 先枚举右端点
假设有个序列: 1 2 3 1 4 3
假设二分的t=1;
那么对于[1,4]区间的众数是num[1]=2 那么有多少个区间满足num[1]=2呢?(这边的套路就要开始了)
我们发现[1,5],[1,6]都满足条件,所以当区间的众数>t 则产生的贡献就是n-i+1
然后我们需要移动左端点,每移动一位区间的众数-1 即可。
最终判断>t的区间个数sum
如果sum>=k 说明二分的t小了,需要调整下限
如果sum<k 说明二分的t大了,需要调整上限
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+1000;
ll a[N],b[N];
ll cnt[N];
int n,k;
bool check(int x)
{
memset(cnt,0,sizeof cnt);
ll ans=0;
for(int i=1,l=1;i<=n;i++)
{
cnt[a[i]]++;
while(cnt[a[i]]>x)
{
ans+=n-i+1;
cnt[a[l]]--;
l++;
}
}
if(ans>=k) return true;
return false;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
int m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
int l=1,r=n;
int ans=0;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid-1,ans=mid;
}
printf("%d\n",ans);
}