基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
收藏
关注
定义一个区间的值为其众数出现的次数。
现给出n个数,求将所有区间的值排序后,第K大的值为多少。
Input
第一行两个数n和k(1<=n<=100000,k<=n*(n-1)/2) 第二行n个数,0<=每个数<2^31
Output
一个数表示答案。
首先想到二分答案,然后在o(n)或者o(nlogn)的复杂度里面判断比二分的X大的有多少个,
这道题学到的重要的思维是枚举区间右端点R,然后动态更新最大的L,那么就可以判断有L个区间符合,这样统计就不会漏掉。这里我的做法比较笨,复杂度应该是o(nlogn^2),用了map瞎搞,明显不是一个好的解法,主要学习枚举R的思维方式。继续努力吧蒟蒻。。。
#include <iostream>
#include <unordered_map>
#include <vector>
#include <cstdio>
using namespace std;
int n;
long long k;
unordered_map<int,int> hashs;
vector<int> v[100005];
const int maxn=100005;
struct po{
int r,l;
};
int arr[maxn];
int cnt[maxn];
long long cal(int x){
long long ret=0;
vector<po> pa;
for(int i=0;i<n;i++){
if(cnt[i]>=x){
int l=v[hashs[arr[i]]][cnt[i]-x];
po p;
p.l=l;
p.r=i;
pa.push_back(p);
}
}
int add=0;
for(int i=0,j=0;i<n;i++){
if(j<pa.size()){
if(j+1<pa.size()&&i>=pa[j+1].r){
j++;
}
if(i>=pa[j].r){
add=max(add,pa[j].l+1);
ret+=add;
}
}
}
return ret;
}
int bs(int a,int b,long long val){
int low=a,high=b;
int ret=0;
while(low<=high){
int mid=(low+high)/2;
ret=mid;
long long x=cal(mid);
if(x==val)
break;
else if(x<val){
high=mid-1;
}
else{
low=mid+1;
}
}
long long x1=cal(ret);
if(x1==val){
return ret;
}
else if(x1<val){
return ret-1;
}
else if(x1>val){
return ret;
}
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++){
scanf("%d",&arr[i]);
hashs[arr[i]]++;
cnt[i]=hashs[arr[i]];
}
unordered_map<int,int>::iterator it=hashs.begin();
for(int i=0;it!=hashs.end();i++,it++){
it->second=i;
}
for(int i=0;i<n;i++){
v[hashs[arr[i]]].push_back(i);
}
cout<<bs(1,n,k)<<endl;
return 0;
}