2020牛客暑期多校训练营(第六场)K题K-Bag(思维)

2020牛客暑期多校训练营(第六场)K题K-Bag(思维)

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");
        }
    }
}

posted @ 2020-07-29 20:57  ccsu_madoka  阅读(151)  评论(0编辑  收藏  举报