牛客多校第六场K-K-Bag

Statement

牛客多校第六场K-K-Bag_第1张图片

题解

  • 我们寻找两个相邻的相同元素
  • 则它们必属于两个不同排列
  • 记它们相距长度为 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 
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");
	}
}

你可能感兴趣的:(2020牛客暑期多校训练营)