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

本文深入探讨了算法竞赛中的一种高效解题策略,通过离散化和前缀和思想来简化数据处理,提升算法效率。特别介绍了如何在面对大规模数据时,运用离散化技巧减少内存消耗,并结合前缀和方法快速计算区间长度,实现O(N)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值