分析
题意即给出一个序列和k,由若干个1-k的全排列组成的序列称为k-bag,如123321132即为3-bag,k-bag的子串为part-k-bag,题目要求我们判断给出的序列是否是part-k-bag。
题目中k有可能大于n。须知没有必要将序列元素的大小保存下来,只将相对大小作为值保存下来就可以了。此题必须离散化,可以通过unordered_map离散化,但低版本的C++并不能使用这个容器,包括noip。离散化的另一种方法是先用sort排序,然后用unique去重,unique()函数的作用是将有序序列中重复的部分放到后面,并返回去重后最后一个数组的地址,其返回值减去数组就是新序列的长度。
lower_bound()函数的作用则返回升序序列第一个大于等于待查找元素的位置。
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5e5+5;
int n,k,a[maxn],b[maxn],pre[maxn],len[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
cin>>n>>k;
memset(pre,0,sizeof(pre));
bool flag=true;
for(int i=1;i<=n;i++)
{
cin>>a[i];
flag&=(a[i]>=1&&a[i]<=k);
b[i]=a[i];
}
if(!flag){cout<<"NO\n";continue;}
sort(b+1,b+1+n);
int cnt=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
int p=1,t=0;
for(int i=1;i<=n;i++)
{
while(!pre[a[p]]&&p<=n)++pre[a[p]],++p;
--pre[a[i]],len[i]=p-i;
}
for(int st=1;st<=min(k,len[1]+1);st++)
{
bool f=1;
for(int i=st;i<=n;i+=k)
{
if(i+len[i]>=n+1)continue;
else if(len[i]^k){f=0;break;}
}if(f){t=1;break;}
}
printf(t?"YES\n":"NO\n");
}
}