题目描述
A sequence is called -bag, if and only if it is put in order by some (maybe one) permutations of
to
. For example,
is a valid
-bag sequence.
Roundgod is not satisfied with kk-bag, so she put forward part-kk-bag, which is a contiguous subsequence of -bag.
Wcy wants to know if the sequence of length is a part-
-bag sequence.
输入描述
The first line contains one integer , denoting the number of test cases. Then TT test cases follow.
The first line of each test case contains two integers .
The second line of each test case contains integers indicate the sequence.
It is guaranteed that , the values of the sequence are between
and
.
输出描述
One line of each test case, if the sequence is a part--bag sequence, print "YES", otherwise print "NO".
示例1
输入
1 8 3 2 3 2 1 3 3 2 1
输出
YES
分析
设给出的序列为 。
首先,若 ,那么给出的
必然不是 part-
-bag,可以直接输出 “NO”。接下来的讨论皆基于
,
的情况。
若 各个元素互不相同,那么
可能恰好是
的全排列,也可能是一个
的全排列的一个子序列;根据
-bag 的定义,此时的
必然是个 part-
-bag。
若 ,那么情况就类似样例
。
的头和尾是
的全排列的一部分,而中部是多个
的全排列。显然,对于
和
,若
,那么两者必然不会在同一个排列中。令
为满足
且
的最小整数,即
。那么
头部的结尾位置最大为
,否则
的头部包含两个相同的数,不满足排列的定义。从
到
枚举
的头部结尾,每次检验接下来的序列是否能构成多个
的全排列即可,当然,检验时,
的尾部是很好识别的。为了做到
的时间复杂度,可以采用双指针。定义两个指针
,
表示当前
头部结尾的位置。最初
,
从
开始,不停地向后找
的全排列,因此可
理解为当前尚未检验过的序列的开头。维护
表示
在当前考察序列(当前考察序列指
这部分序列)内出现的次数;
的中部会有多个全排列,用
表示当前正在检验的全排列的编号,从
开始记录。假设已经检验完
个全排列,当前正在检验第
个全排列,由于
表示还未检验到的序列开头,那么当且仅当
时,前面有
个全排列;否则,说明当前的
作为头部的结尾不能使
成为 part-
-bag,应当继续枚举
。若
一直枚举到
还未找到
成为 part-
-bag 的方案,那么
就不是 part-
-bag。
注意要用 和
,
和
则容易超时。
代码
/****************************************************************** Copyright: 11D_Beyonder All Rights Reserved Author: 11D_Beyonder Problem ID: 2020牛客暑期多校训练营(第六场) Problem K Date: 8/27/2020 Description: Double Pointer *******************************************************************/ #include<unordered_map> #include<cstdio> #include<iostream> #include<unordered_set> using namespace std; const int N=500004; int _; int a[N]; int n,k; int main(){ for(cin>>_;_;_--){ scanf("%d%d",&n,&k); int i; bool flag=0; for(i=1;i<=n;i++){ scanf("%d",a+i); } for(i=1;i<=n;i++){ //超出范围 if(a[i]<1||a[i]>k){ flag=1; break; } } if(flag){ puts("NO"); }else{ unordered_set<int>ex; int d; for(i=1;i<=n;i++){ if(ex.count(a[i])){ //保证d是满足条件的最小整数 d=i; break; }else{ ex.insert(a[i]); } } if(ex.size()==n){ //互不相同的n个数 puts("YES"); }else{ bool is=1; int l=1,r=2; int ID=1;//当前要找的全排列编号 int num=0;//一个全排列中已经遍历的数字个数 unordered_map<int,int>cnt; while(r<=n){ if(l==d){ is=0; break; } bool find_permutation=1; while(r<=n){ //若r能一直检验到n //那么这个l就是合法的 if(cnt[a[r]]==ID-1){ //a[r]可以在第ID个排列内 cnt[a[r]]++; r++; num++; if(num==k){ //找到一个全排列 //继续找下一个 num=0; ID++; } }else{ //减去贡献 num--; cnt[a[l+1]]--; l++; break; } } } puts(is?"YES":"NO"); } } } return 0; }