牛客 K-Bag

题目链接

题目分析:

该题目要求的是判断给出的序列是否满足part-k-bag。而容易发现,如果序列中连续的K个数均没有重复,那么这个连续子序列就是k-bag(因为值的范围是1-k,如果k个数没有重复,必定取完了1-k的所有数)。
所以现在每个位置能否构成k-bag就可以通过判断以它为起点的最长无重复连续序列的长度来确定。这样我们就可以每隔k个数检查一次来判断整个串是否为part-k-bag了。但是还有一个问题,检查的起始位置该从哪里开始?由于part-k-bag的两端不一定是完整的k-bag,所以检查的时候要考虑到。前端的话由于无法确定,可以选择遍历min(k-1,len[0])个位置(len[ i ]表示每个位置对应的最长~~的长度)作为起点。后端只需在判断时,多加入判断: j + len[ j ] == n 即可( j 表示检查的位置)。

做法:

尺取法预处理每个位置对应的最长~~,存入数组。然后找到起始位置的范围,判断每个位置作为起始位置时后面的每隔k个的点是否符合k-bag,全部符合则这个起始位置合法。但凡有一个合法,该序列都为part-k-bag。

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int MAX_N=5e5+5;
int arr[MAX_N];
int main()
{
	int T;
    scanf("%d",&T);
	while(T--)
	{
		int n,k;
        scanf("%d%d",&n,&k);
		for(int i=0;i<n;i++)scanf("%d",arr+i);
		set<int> myset;
		int l=0,r=0;
		while(l<n)
		{
			while(r<n&&!myset.count(arr[r]))myset.insert(arr[r++]);
			myset.erase(arr[l]);
			arr[l]=r-l;//每一个点,无重复的最大长度
			l++;
		}
		int len=min(arr[0],k-1);
		bool f=false;
		for(int i=0;i<=len&&!f;i++)
		{
			f=true;
			for(int j=i;j<n&&f;j+=k)
			{
				if(arr[j]>=k||arr[j]+j==n)continue;
				f=false;
			}
		}
		cout<<(f?"YES":"NO")<<'\n';
	}
	return 0;
}
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页