题目大意: 定义名为K-bag的一类数组:由几个k的全排列头尾链接组成的数组。
如一个3-bag: 【1 2 3 3 2 1 2 1 3 】 是由【1 2 3】【3 2 1】【2 1 3】连接而成的数组。
给你一个长度为n的数组和一个数k,(1<=n<=2e6,1<=k<=1e9)问其是否是一个K-bag的子数组(连续)。
【2 3 1 2】=>【2 3 1 || 2 (1)(3)】=> YES
解:
若数组【a1,a2,a3,.....,an-1,an】为K-bag子串。则在数组前后各自添上一些数后,数组变为K-bag。
即【b1,b2,...,a1,a2...,an,c1,c2...,cx]为一个k-bag。定义:k-bag的分割点————k-bag中的俩个连续的全排列的分开的位子.
如【1 2 (3) 3 2 (1) 2 1 (3)】中加括号的数即为此3-bag的分割点。
注意到分割点的前k个数合为一全排列。
则数组中某数ai能否作为分割点,取决于其前k个数是不是一个全排列,即[ai-k+1,ai]中每个数只出现1次。
那么,若数组中间隔为k的某一数列(【ai,ai+k,ai+2k,...】),均可作为分割点,则数组合法。
分割点的判断:
定义一个bool vis【maxn】数组。用于维护前缀数组的信息。
vis【i】表示i作为分割点后,【a1,a2....,ai】是否合法。
合法取决于,ai的前k个数中,没有一个数出现了两次,且vis【i-k】==true(即【a1,...,ai-k】也合法)
然后前后各扫一遍数组,统计区间每个长度为k的区间是否有某个数出现次数大于1即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
const int inf=1e8;
void in(int &x){
    int y=1;char c=getchar();x=0;
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    x*=y;
}
void o(int x) {
    if (x < 0){
        putchar('-');
        x = -x;
    }
    if (x > 9)o(x / 10);
    putchar(x % 10 + '0');
}
int read(){
    int  res=0;
    int  y=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c<='9'&&c>='0'){res=(res<<1)+(res<<3)+c-'0';c=getchar();}
    return res*y;
}
int n,k;
int a[maxn];
int cnt[maxn];
vector<int>v;
int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
bool vis[maxn];//vis[i]表示是否可以在此处可以作为k-bag中分割点,且vis【i-k】=true。(确立一个点作为分割点以后,则其余分割点也yi'j确立。
int sum2;//区间个数大于2的数的个数
void add(int x){//加上一个数
    x=getid(x);
    if(cnt[x]==1){sum2++;}//x的个数从1变为2,sum2+=1;
    cnt[x]++;
}
void del(int x){//删去一个数
    x=getid(x);
    if(cnt[x]==2){sum2--;}//2->1,sum-=1
    cnt[x]--;
}
void getvis(){
    sum2=0;
    for(int i=1;i<=n;i++){vis[i]=false;cnt[i]=0;}//初始化
    vis[0]=true;//0前k个数未确定,必定合法
    for(int i=1;i<=n;i++){
        add(a[i]);
        if(i<=k){if(sum2==0)vis[i]=true;}//区间小于k ,只需加上
        else{
            del(a[i-k]);//删去一个数
            if(sum2==0&&vis[i-k]){vis[i]=true;}//判断合法性
        }
    }
}
bool fan(){
    sum2=0;
    for(int i=1;i<=n;i++){cnt[i]=0;}
    for(int i=n;i>n-k&&i>=1;i--){
        add(a[i]);
        if(sum2==0&&vis[i-1]){return true;}//若后缀前缀均数组合法,YES
    }
    return false;
};
bool check(){
    for(int i=1;i<=n;i++){
        if(a[i]>k){
            printf("NO\n");
            return false;
        }
    }
    return true;
}
signed main(){
    int T;
    in(T);
    while(T--){
        in(n);in(k);v.clear();
        for(int i=1;i<=n;i++){in(a[i]);v.push_back(a[i]);}//读入
        if(!check()){continue;}//找找有没有数比k还大
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());//v用于离散化
        getvis();//求前缀合法性
        if(fan()){printf("YES\n");}//求后缀合法性并判断
        else {printf("NO\n");}
    }
    return 0;
}