2020牛客暑期多校训练营(第六场)K题K-Bag(思维)
2020牛客暑期多校训练营(第六场)K题K-Bag(思维)
题意:求一个字符串是不是任意个1到k的排列的组合的子串,即首尾不需要1到k全都有,中间任意端都要有。
题解:很明显任意两个相同的数字不在一个排列中,我们可以利用这一特点求出每个位置第一个不合法的位置(不能在一个排列)在哪,然后枚举第一段的以何位置截止,求之后中间端长度是否刚好为k既可,如果能走到最后,说明为part-K-Bag。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int t,n,k,a[500007],b[500007],ma[500007],to[500007],len;
int check(int p){
int now=p;
while(now<=n){
if(to[now]-now==k){
now=to[now];
}
else return 0;
}
return 1;
}
void init(){
memset(ma,0,sizeof(ma));
memset(to,0,sizeof(to));
memset(b,0,sizeof(b));
}
int main(){
scanf("%d",&t);
while(t--){
init();
scanf("%d%d",&n,&k);
int m=0,ok=1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(a[i]>k||a[i]<=0){
ok=0;
}
b[++m]=a[i];
}
if(ok==0){
printf("NO\n");
continue;
}
sort(b+1,b+1+m);
m=unique(b+1,b+1+m)-b-1;
for(int i=1;i<=n;++i){
a[i]=lower_bound(b+1,b+1+m,a[i])-b;
}
int len=n+1;
for(int i=n;i>=1;i--){
if(ma[a[i]]==0){
to[i]=i+k;
}
else{
to[i]=ma[a[i]];
}
len=min(len,to[i]);
ma[a[i]]=i;
}
for(int i=n-1;i>=1;i--){
to[i]=min(to[i],to[i+1]);
}
ok=0;
for(int i=1;i<len;i++){
if(check(i+1)==1){
ok=1;
}
}
if(ok)printf("YES\n");
else{
printf("NO\n");
}
}
}