本题目是给定一个序列,该序列是1到k的不同排列的拼接中切出的一段,让判断下一个排列的开端可能在哪里。
那么,首先用滑动队列,求出以i位置为结尾的长为k的序列是否可以构成一个排列,要注意两边的考虑,
然后枚举开始点,判断后面的排列是否合法即可。这样枚举起点,加上判断总共的复杂度接近o(n)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 201010;
int cnt[N],ok[N],n,k,a[N];
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d",&k,&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i])==1;
}
memset(cnt,0,sizeof(cnt));
memset(ok,0,sizeof(ok));
int num=0,L=0,R=0;
for(int i=1;i<n+k;i++){
while(R<i&&R<n){
R++; cnt[a[R]]++;
if(cnt[a[R]]==1) num++;
else if(cnt[a[R]]==2) num--;
}
while(L<i-k){
L++; cnt[a[L]]--;
if(cnt[a[L]]==1) num++;
else if(cnt[a[L]]==0) num--;
}
if(num==R-L||(i>n&&num==n-L)) ok[i]=1;
} ok[n+k]=1;
int res=0;
for(int i=1;ok[i] && i<=k;i++){
int ff=0;
for(int j=i+k;;j+=k){
if(!ok[j]) break;
if(j>=n){ff=1; break;}
}
res+=ff;
}
if(n<k && ok[n]) res+=k-n;
printf("%d\n",res);
}
return 0;
}