2020牛客暑期多校训练营(第六场)K-Bag (补题)

https://ac.nowcoder.com/acm/contest/5671/E

题解:如果序列是k-bag的连续子串的话,满足一下三种条件之一:

1.一个部分k-bag的前缀+若干个完整的k-bag+一个部分k-bag的后缀

2.一个部分k-bag的前缀+一个部分k-bag的后缀

3.一个部分k-bag

判断部分k-bag:只需要判断区间内不同的数的个数是否等于区间的长度。

这里cnt1[i]表示1~i区间内有多少不同的数,cnt2[i]表示n~i区间内有多少不同的数

判断完整的k-bag:连续序列[l,r],维护 sum 和 xor ,sum = l + ( l + 1 ) + ... + ( r - 1 ) + r ,xor = l ^ ( l + 1 ) ^ ... ^ ( r - 1 ) ^ r ,形成一个二元对 < sum , xor >,这个二元对和 [ l , r ] 是一一对应的.(这里为防止冲突,对每一个值乘以131,然后再求和,异或)

对于n>k,只能是条件1和2.我们枚举[1,k]作为第一个完整k-bag的起点,然后判断每一个长度为k的区间是否满足,根据预处理的前缀和与异或和

对于k>=n,只能是条件2和3.那么我们枚举断点判断前部分和后部分就行了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
ll a[maxn],n,k;
ll sum[maxn],Xor[maxn],S,X;
unordered_map<ll,ll> mp;
int cnt1[maxn],cnt2[maxn];

bool check(int st) {
	for(int i=st;i<=n;i+=k) {
		int l=i,r=i+k-1;
		if(r<=n) {
			if(sum[r]-sum[l-1]!=S||(Xor[r]^Xor[l-1])!=X)
				return false;
		} else return cnt2[l]==n-l+1;
	}
	return true;
} 
void init() {
	mp.clear();
	cnt1[0]=0;
	for(int i=1;i<=n;i++) {
		cnt1[i]=cnt1[i-1];
		if(!mp[a[i]]) cnt1[i]++;
		mp[a[i]]++;
	}
	mp.clear();
	cnt2[n+1]=0;
	for(int i=n;i>=1;--i) {
		cnt2[i]=cnt2[i+1];
		if(!mp[a[i]]) cnt2[i]++;
		mp[a[i]]++;
	}
}
bool solve() {
	if(k<n) {
		S=X=0;
		for(int i=1;i<=k;i++) S+=(i*131),X^=(i*131);
		for(int i=1;i<=k;i++) {
			if(cnt1[i-1]!=i-1) {
				break;
			}
			if(check(i)) return true;
		}
	} else {
		for(int i=2;i<=n;i++) {
			if(cnt1[i-1]==i-1&&cnt2[i]==n-i+1) return true;
		}
	}
	return false;	
}
signed main() {
	int test; scanf("%d",&test);
	while(test--) {
		scanf("%lld%lld",&n,&k);
		int flag=0;
		for(int i=1;i<=n;i++) {
			scanf("%lld",a+i);
			if(a[i]<1||a[i]>k) flag=1;
			a[i]=a[i]*131;
			sum[i]=sum[i-1]+a[i];
			Xor[i]=Xor[i-1]^a[i];
			//每一个数乘以131然后哈希,防止冲突 
		}
		if(flag) {
			puts("NO");
			continue;
		}
		init();
		if(solve()) puts("YES");
		else puts("NO");
	}
	
	
	
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值