Sixth K-K-bag (thinking)

Title here

Meaning of the question: define k-bag as a sequence composed of several 1 to k sequences, each 1~k sequence can only contain k numbers, that is, it cannot be repeated, such as 1 2 3 2 3 1 3 2 1 is called one 3-bag. A continuous subsequence of k-bag is also called part k-bag. Now given you n numbers and k, ask you whether these n numbers are a part k-bag.

Idea: We first use a len array to determine the length of the unique sequence starting from the current position. When encountering the current position of len[i] == k, it means that the middle part of the sequence can form k non-repetitive sequences, so that the length of k is incremented each time, if the length of len is always equal to k, it is feasible .
Because the given sequence is incomplete, in addition to the complete part in the middle, there may be some parts that need to be added before and after to form a k-sequence. Therefore, we need to use the uncircled parts in front as the starting point for enumeration, because we don’t Knowing that the first few incomplete ones can form a complete k-sequence, so enumerate the position from the starting point to the point where the beginning position is repeated for the first time. Because going further back, the previous ones cannot form a k-sequence, and when a When the position of the point plus len is greater than n, it means that there are no repeated points after this point, and this part can also be completed as a k sequence.

This question k <= 1e9, if you use an array to record the current number of occurrences, it will not be displayed, so you need to discretize the given a array

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 5e5+7;
int a[MAXN],b[MAXN],len[MAXN],pre[MAXN];
int n,k;

void lisan()
{
    
    
	for(int i = 1;i <= n;i ++){
    
    
		scanf("%d",&a[i]);
		b[i] = a[i];
	}
	sort(b+1,b+1+n);
	int cnt = unique(b+1,b+1+n)-b-1;
	for(int i = 1;i <= n;i ++){
    
    
		a[i] = lower_bound(b+1,b+1+cnt,a[i])-b;
	}
}

int main()
{
    
    
	int t;
	scanf("%d",&t);
	while(t--){
    
    
		scanf("%d%d",&n,&k);
		lisan();
		int pos = 1,flag = 0;
		for(int i = 1;i <= n;i ++){
    
    
			while(!pre[a[pos]] && pos <= n)
				++pre[a[pos]],pos++;//一直没有出现过 就是一直都没有重复就往后加就行了
			--pre[a[i]];//当了前位置 把这个位置的减掉后面的相同的才可以进来
			len[i] = pos - i;
		}
		int ed = min(k,len[1]+1);//来确定起点有几种可能性 要么与开头第一个重复,要么就是k 超过k也没有意义了
		for(int i = 1;i <= ed;i ++){
    
    
			int f = 1;
			for(int j = i;j <= n;j += k){
    
    
				if(j + len[j] > n) continue;
				else if(len[j] != k){
    
    
					f = 0;//这个起点不可行
					break;
				}
			}
			if(f == 1){
    
    //找到了一个可行的起点 就完成了
				flag = 1;
				break;
			}
		}
		if(flag) puts("YES");
		else puts("NO");
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45672411/article/details/107663552