码迷,mamicode.com
首页 > 其他好文 > 详细

【题解】51nod 1686第K大区间

时间:2018-07-29 21:14:32      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:size   col   read   固定   +=   sign   names   mem   tchar   

  成功的秘诀,在于克服自己看题解的冲动……【笑哭】。自己A掉这题还是灰常开心的~

  以及爱死 two - pointer ! two - pointer 大法是真的好哇……这个题目有上一题的经验:求第\(K\) 大 --> 二分第 \(K\) 大的值 --> 检验当前二分的值排名是第几。而这样之所以可以解决问题在于:直接求第 \(K\) 并不好求,而检验一个值的排名却相对容易。所以我们现在的问题就转化为了如何计算出区间的值 \(>= mid\) 的区间的个数?

  做题之前先找规律 & 性质。这里我们注意到:如果我们固定一个右端点,那么区间的值是随着区间的长度单调不减的。……好像和 two - pointer有点像?如果当前的 \(l --> r\) 区间满足区间的值 \(>= mid\), 则 \(1 -- > l - 1\) 也同样是满足的。这样,只需要在找到第一个 \(l, r\)之后不断右移左端点就可以了。计算区间众数可以采取和莫队一样的处理方法。

  以及……要开 long long??? 我也不知道发生了什么……

#include <bits/stdc++.h>
using namespace std;
#define maxn 200000
#define int long long
int n, tot, K, now, a[maxn], b[maxn];
int ans, num[maxn], cnt[maxn];
map <int, int> Map;

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < 0 || c > 9) { if(c == -) k = -1; c = getchar(); }
    while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar();
    return x * k;
}

void Add(int x)
{
    num[cnt[a[x]]] --; cnt[a[x]] ++; num[cnt[a[x]]] ++;
    if(cnt[a[x]] > now) now = cnt[a[x]];
}

void Minus(int x)
{
    if(now == cnt[a[x]] && num[cnt[a[x]]] <= 1) now --; 
    num[cnt[a[x]]] --; cnt[a[x]] --; num[cnt[a[x]]] ++;
}

bool Check(int mid)
{
    memset(num, 0, sizeof(num));
    memset(cnt, 0, sizeof(cnt));
    now = 0; int ans = 0;
    for(int l = 1, r = 1; r <= n; r ++)
    {
        if(now < mid) Add(r);
        while(l <= r && now >= mid) Minus(l), l ++;
        ans += l - 1;
    }
    if(ans >= K) return 1;
    else return 0;
}

signed main()
{
    n = read(), K = read();
    for(int i = 1; i <= n; i ++) a[i] = b[i] = read();
    sort(b + 1, b + 1 + n); b[0] = -1;
    for(int i = 1; i <= n; i ++) 
        if(b[i] != b[i - 1]) Map[b[i]] = ++ tot;
    for(int i = 1; i <= n; i ++) a[i] = Map[a[i]];
    int l = 1, r = n;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(Check(mid)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    printf("%lld\n", ans);
    return 0;
}

 

【题解】51nod 1686第K大区间

标签:size   col   read   固定   +=   sign   names   mem   tchar   

原文地址:https://www.cnblogs.com/twilight-sx/p/9387579.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!