51nod 1686 第K大区间 二分瞎搞
2017-03-22 20:43
337 查看
题目:
定义一个区间的值为其众数出现的次数。
现给出n个数,求将所有区间的值排序后,第K大的值为多少。
题解:
答案明显单调,我们考虑二分答案.
转化为判定问题后我们需要观察到一个性质:
如果一个区间的价值已经 >= mid了,那么这个无论左右端点向外延伸多少,区间价值一定仍然 >= mid
所以我们可以考虑找出所有的最小满足限制的区间,然后计算出可延伸区间。
所以我们枚举右端点,根据右端点找出对应的左端点,然后统计答案.
我们发现:根据右端点向右移动,左端点一定也向右移动。
所以我们使用双指针法,每一次计算出右端点所代表的值的上mid-1次出现的位置
用这个位置和左端点指针取max,每一次让ans += 所有<=下标左端点的点的个数.
单次判定\(O(n)\),总体\(O(nlogn)\)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; inline void read(int &x){ x=0;char ch;bool flag = false; while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true; while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x; } inline void read(ll &x){ x=0;char ch;bool flag = false; while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true; while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x; } const int maxn = 120000; int last[maxn],nxt[maxn]; int b[maxn],n,a[maxn],c[maxn],pos[maxn]; inline void init(){ memset(last,0,sizeof last); memset(nxt,0,sizeof nxt); memset(b,0,sizeof b); } inline ll check(int val){ ll ret = 0; init();memset(c,0,sizeof c); for(int i=1;i<=n;++i){ last[i] = c[a[i]]; c[a[i]] = i; }memset(c,0,sizeof c); for(int i=n;i>=1;--i){ nxt[i] = c[a[i]]; c[a[i]] = i; } memset(c,0,sizeof c); memset(pos,0,sizeof pos); for(int i=1;i<=n;++i){ if(++c[a[i]] == 1) pos[a[i]] = i; if(c[a[i]] == val) b[i] = pos[a[i]]; else if(c[a[i]] > val){ b[i] = nxt[b[last[i]]]; } } if(val == 1) for(int i=1;i<=n;++i) b[i] = i; for(int L=0,R=1;R <= n;++R){ L = max(L,b[R]); ret += L; } return ret; } int main(){ read(n);ll k;read(k); for(int i=1;i<=n;++i){ read(a[i]);b[i] = a[i]; } sort(b+1,b+n+1); for(int i=1;i<=n;++i){ a[i] = lower_bound(b+1,b+n+1,a[i]) - b; } int l = 1,r = n,ans = 0; while(l <= r){ int mid = (l+r) >> 1; if(check(mid) >= k) ans = mid,l = mid+1; else r = mid-1; } printf("%d\n",ans); return 0; }
相关文章推荐
- 【二分+Two Pointers】51Nod 1686 第K大区间
- 解题报告:51nod 1686 第K大区间 二分+尺取
- 51nod 1686 第K大区间【离散化+二分】
- 51nod 1686 第K大区间【离散化+二分】
- 51nod-1686 第K大区间(二分+尺取法)
- 51nod 1686 第K大区间 (二分+滑动窗口+离散化)
- 51NOD 1686 第K大区间 二分
- 51Nod【1686】——1686 第K大区间(尺取+二分)
- 51nod 1686 第K大区间 二分好题
- 51nod 1686-第K大区间(离散化+二分+尺取)
- 51nod 1686 第K大区间(二分 尺取)
- 51nod-1686 第K大区间
- 51nod 1686 第K大区间
- 51nod 40 第K大区间 二分+尺取
- 51Nod 1686(第K大区间)
- 51Nod-1686-第K大区间
- 51nod 第K大区间2(二分+树状数组)
- 【51nod】 第K大区间2(二分+树状数组)
- ACM学习历程—51NOD 1685 第K大区间2(二分 && 树状数组 && 中位数)
- 51Nod 1686 第K大区间(离散化+尺取法)