CF1676F Longest Strike 题解

题意

给你一个长度为 $n$ 的序列 $a$ 和一个整数 $k$,你要求一个区间 $[l,r]$ 满足:

  • 对于任何整数 $x∈[l,r]$,$x$ 在 $a$ 中的出现次数不少于 $k$ 次。
  • 最大化 $r-l$。

无解输出 -1

思路

看到出现次数,先把 $a$ 装进桶 $c$ 里,

发现装不进去,就离散化一下再装进桶 $c$ 里。

令 $l,r$ 存正在处理的区间,$x,y$ 存目前最大的区间,$s$ 存目前最大区间的大小。

接着按离散化后的 $a_i$ 从小到大扫一遍:

  • 如果 $c_i≥k$,区间可以包含 $a_i$,则 $r\gets a_i$,
    1. 如果 $a_i≠a_{i-1}+1$,不能与之前的区间接上,则“另起炉灶”,$l\gets a_i$。
    2. 否则 $l$ 保持原值不变。
    3. 用 $l,r$ 更新 $x,y,s$。
  • 否则区间不能包含 $a_i$,$l\gets a_{i+1},r\gets a_{i+1}$。

注意这里 $a_1$ 必须“另起炉灶”,因为 $a_1$ 之前没有别的区间。

所以我们要手动让 $a_1≠a_0+1$,$a_0\gets-1$ 即可。

最后如果 $s$ 从未被更新过就是无解,否则解为 $[x,y]$。

代码

#include <cstdio>
#include <algorithm>
#define h(x) lower_bound(a + 1, a + m + 1, x) - a
using namespace std;
int T, n, m, k, s, l, r, x, y, a[200050], b[200050], c[200050];
int main()
{
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &n, &k);s = -1;
        for(int i = 1;i <= n;++i) scanf("%d", &a[i]), b[i] = a[i];
        sort(a + 1, a + n + 1);m = unique(a + 1, a + n + 1) - a - 1;
        for(int i = 1;i <= m;++i) c[i] = 0;
        for(int i = 1;i <= n;++i) ++c[h(b[i])];a[0] = -1;
        for(int i = 1;i <= m;++i)
            if(c[i] >= k)
            {
                if((r = a[i]) != a[i - 1] + 1) l = a[i];
                if(r - l > s) s = r - l, x = l, y = r;
            }
            else l = r = a[i + 1];
        if(s == -1) puts("-1");
        else printf("%d %d\n", x, y);
    }
    return 0;
}
posted @ 2022-05-11 15:02  5k_sync_closer  阅读(2)  评论(0编辑  收藏  举报  来源