一、题意
这题刚看到想了5分钟左右没有啥思路(在上某大佬的某节课发现并不能听懂也似乎没啥实践指导意义,遂怒写一题)。于是查了下看看对方的代码,正准备进行:看到半懂,复刻,重写若干遍这种流程的时候,发现其思路意外的简单。
题意复制如下:
定义一个区间的值为其众数出现的次数。
现给出n个数,求将所有区间的值排序后,第K大的值为多少。
第一行两个数n和k(1<=n<=100000,k<=n*(n-1)/2)
第二行n个数,0<=每个数<2^31
二、题解
用尺取法统计大于某个值得区间的个数,之后可以在ON的时间内搞定检查,因为必然具有单调性,于是可以进行二分。
三、代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define veci vector<int> const ll MAXN=100233; ll arr[MAXN]; ll numbers[MAXN]; ll n,k; int vis[MAXN]; inline int checkPos(int i) { return lower_bound(numbers,numbers+n,arr[i])-numbers; } ll check(int limit) { ll ans=0; memset(vis,0,sizeof(vis)); int spos=-1; for(int i=0;i<n;++i) { vis[arr[i]]++; while(vis[arr[i]]>=limit) { ans+=n-i; spos++; vis[arr[spos]]--; } }return ans; } int search(int a,int b) { if(a==b-1)return a; int mid=(a+b)/2; if(check(mid)<k)search(a,mid); else search(mid,b); } void init() { for(int i=0;i<n;++i) { cin>>arr[i]; numbers[i]=arr[i]; }sort(numbers,numbers+n); for(int i=0;i<n;++i) { arr[i]=checkPos(i); } cout<<search(1,n); } int main() { cin.sync_with_stdio(false); cin>>n>>k;init(); return 0; }