Statement
题解
- 我们寻找两个相邻的相同元素
- 则它们必属于两个不同排列
- 记它们相距长度为 l e n [ i ] len[i] len[i]
- 枚举起点(无重复)之后往后面跳
- 如果有一处长度不是 k k k就不行
细节
- 由于过大的元素( [ 1 , 1 0 9 ] [1,10^9] [1,109])
- 如果不想用慢慢慢的map或比赛用不了的unordered_map
- 就只能进行离散化
- 完整版
for(int i=1;i<=n;i++)
scanf("%d",a+i),b[i]=a[i];
sort(b+1,b+n+1);
cnt=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
Update 1(2020.7.28)
详细解释 p r e [ i ] pre[i] pre[i]的作用
- 这是一个很巧妙的想法
- i n s t e a d o f instead~of instead of记录每个区间的左右端点(这样很麻烦而且容易搞错)
- 我们在区间开始的位置 + + p r e [ a i ] ++pre[a_i] ++pre[ai]结束时 − − p r e [ a i ] --pre[a_i] −−pre[ai]
- p r e [ a i ] = = 0 pre[a_i]==0 pre[ai]==0即表示没有出现
- 利用前缀和的思想,统计每个区间长度并保存至 l e n [ i ] len[i] len[i]
- 总复杂度 O ( N ) O(N) O(N)(不含离散化)
实现
#include <bits/stdc++.h>
const int N=5e5+10;
using namespace std;
int T,n,k,a[N],b[N],cnt,pre[N],len[N];
int main(){
scanf("%d",&T);
while(T--){
memset(pre,0,sizeof(pre));
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",a+i),b[i]=a[i];
sort(b+1,b+n+1);
cnt=unique(b+1,b+n+1)-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;
记它们相距长度为len[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;
如果有一处长度不是k就不行
else if(len[i]^k){f=0;break;}
}if(f){t=1;break;}
}printf(t?"YES\n":"NO\n");
}
}