Description
给定一个长度为 (n) 的序列,判定它是否为一个由多个 (1 sim k) 全排列顺序连接起来的序列的子串。
Solution
首先如果原序列中有不在 ([1,k]) 中的元素则直接退出。
考虑每个元素和它上一次出现的位置,如果其间的距离 (le k),则显然 ([lastpos,pos-1]) 之间必有一个分割点。
环上差分有点麻烦,考虑直接模拟,用 (sum) 记录当前的前缀和,每经过一个位置就将这个前缀和加到这个位置取模后对应位置的 (ans) 上即可。
正确性的保证基于我们所列出的所有区间其长度一定 (le k)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n,k,a[N],b[N],ans[N];
void solve()
{
scanf("%lld%lld",&n,&k);
map <int,int> mp;
int tot=0;
for(int i=0;i<=n+1;i++) a[i]=b[i]=ans[i]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(a[i]>k)
{
puts("NO");
return;
}
int pos=i,lastpos=mp[a[i]];
if(lastpos>0 && pos-lastpos<k)
{
b[lastpos]++;
b[pos]--;
tot++;
}
mp[a[i]]=i;
}
int sum=0;
for(int i=1;i<=n;i++)
{
sum+=b[i];
ans[i%k]+=sum;
}
if(*max_element(ans,ans+n+1)>=tot)
{
puts("YES");
}
else
{
puts("NO");
}
}
signed main()
{
int t;
scanf("%lld",&t);
while(t--)
{
solve();
}
return 0;
}