F. Longest Strike[双指针详解]

Longest Strike

题面翻译

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

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

无解输出 -1

例如, a = [ 11 , 11 , 12 , 13 , 13 , 14 , 14 ] , k = 2 a=[11,11,12,13,13,14,14],k=2 a=[11,11,12,13,13,14,14],k=2 时:

  • l = 12 , r = 14 l=12,r=14 l=12,r=14 不满足条件,因为 12 12 12 只出现了 1 1 1 次。
  • l = 13 , r = 14 l=13,r=14 l=13,r=14 满足条件,因为 13 13 13 出现了 2 2 2 次, 14 14 14 出现了 2 2 2 次。
  • l = 11 , r = 11 l=11,r=11 l=11,r=11 满足条件,因为 11 11 11 出现了 2 2 2 次。

满足条件且 r − l r-l rl 最大的区间是 l = 13 , r = 14 l=13,r=14 l=13,r=14
在这里插入图片描述在这里插入图片描述

样例 #1

样例输入 #1

4
7 2
11 11 12 13 13 14 14
5 1
6 3 5 2 1
6 4
4 3 4 3 3 4
14 2
1 1 2 2 2 3 3 3 3 4 4 4 4 4

样例输出 #1

13 14
1 3
-1
1 4

思路:
注意题目里面的x是任何属于l与r区间的数,所以我们取得这个区间一定是满足单调递增且公差是1的一组序列,然后把这些数放入一个全新的a序列里面,用双指针判断即可
判断一个序列是否要结束
1.次数不够了要终止
2.出现的断要终止
3.到了结尾要终止

即:if (a[i] - a[i - 1] != 1 || mp[a[i]] < m||i==k+1)
三种情况出现一个就要结束

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
using namespace std;
int t, n, m;
int w[200005];
int a[200005];
int main()
{
    cin >> t;
    while (t--)
    {
        int sst=0, ed=0;//上限与下限
        bool vis = 0;//判断能不能构成
        int ans = 0;
        map<int, int>mp;//判断每一个数出现的个数
        map<int, int>st;
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            cin >> w[i], mp[w[i]]++;//个数++
            if (mp[w[i]] >= m)
                vis = 1;//这样肯定就是合法的,
                //即不用输出-1
        }
        sort(w + 1, w + 1 + n);//排个序方便判断
        int k = 1;
        for (int i = 1; i <= n; i++)
        {
            if (!st[w[i]])
                a[k++] = w[i], st[w[i]] = 1;
        }      
        k--;//k多加了一次要剪掉
        int r = 1;
        int l = 1;
        a[0] = a[1] - 1;
        while (l <= k && mp[a[l]] < m) l++;//确定l下限的位置
        r = l;
        for (int i = l; i <= k+1; i++){
            if (a[i] - a[i - 1] != 1 || mp[a[i]] < m||i==k+1){
                r = i - 1;
                if (ans < r - l + 1) {
                //长度变大,记得更新边界
                    sst = l;
                    ed = r;
                    ans = r - l + 1;
                }
                l = i;
                while (l <= k && mp[a[l]] < m) l++;//确定l下限的位置
                i = l;
            }
        }
        if (!vis) cout << -1 << endl;//无答案
        else 
        cout << a[sst] << " " << a[ed] << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值