专栏文章

题解:P14359 [CSP-J 2025] 异或和 / xor(民间数据)

P14359题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minfn66o
此快照首次捕获于
2025/12/02 01:38
3 个月前
此快照最后确认于
2025/12/02 01:38
3 个月前
查看原文
提供一个方便理解的思路
题目读完后,很明显是一个前缀异或,用一个数组存当前下标之前的所有数的异或和,调用跟前缀和一样,例:: 求区间 [l,r][l,r] 的异或和
CPP
a[l-1] xor a[r]
那什么情况下是最优的呢,当区间长度为 11 时是最具性价比的。遍历整个序列,把所有长度为 11 且等于 kk 的区间都标记,这样我们可以得到这样的一个序列
样例 1:1:
2103
给第一项,也就是 22 那一项打上标记,表示已经选取,接下来继续往后遍历如果不满足等于 kk ,就从当前下标往前遍历,直到遇到标记过的数字或边界。这样每一次往前遍历,可以遍历到的所有数字都是没有标记,即未选择过的。那这样无论区间长度,都是最优的。
这里提供一个样例::
CPP
5 2 
1 3 2 1 2
CPP
3
对所有长度为 11 且等于 kk 的区间标记之后长这样
13标记1标记
可以看到序列被分为两部分,对每个部分进行的每一项都往前遍历,找到第一个满足异或和为 kk 的区间,然后标记当前下标 ii 。因为遇到标记过的会结束循环,所以遍历的都为未被选择的项目,不存在更优解。
ACAC代码::
CPP
#include<bits/stdc++.h>
using namespace std;
long long a[500001],b[500001],c[500001];
//a存序列,b存前缀异或,c为标记数组
int main(){
	long long n,k,ans=0;//ans记录区间数量
	cin>>n>>k;
	for(long long i=1;i<=n;i++){
		cin>>a[i];
		b[i]=b[i-1] xor a[i];//记录从1到i的异或和
		if(a[i]==k){//标记长度1的区间
			c[i]=1;
			ans++;
		}
		else{
			for(long long j=i-1;j>=1;j--){
				if(c[j]==1) break;//遇到标记过的就退出循环
				if((b[i] xor b[j-1])==k){
					ans++;
					c[i]=1;//往前遍历,只需标记i项
					break;
				}
			}
		}
	}
	cout<<ans;
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...