题目描述
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;
} 
京公网安备 11010502036488号