【题解】CF1438E Yurii Can Do Everything

我的垃圾做法好像和别人有些不同,分享一下。

题目传送门:luoguCF

规定:记序列 s 表示序列 a 的前缀和,highbit(x) 表示数 x 的最高位,序列 a 值域为 m

首先考虑枚举一个端点找答案,不妨枚举 l,然后寻找枚举 r 的性质来减少枚举。

考虑左端点 l,不难发现对于一个 l 之后最小的位置 k 满足 highbit(sksl)>highbit(al)k 之后的所有位置 j 若要作为右端点 r,因为 al 的第 highbit(sj1sl) 位必然为 0,所以 j 必须满足 highbit(aj)highbit(sj1sl),这时,对于 j 后的每一个位置 j,显然 highbit(sj1sl) 大于 highbit(sj1sl),而 highbit 至多增大到 log2m,所以 k 后满足条件的右端点数量最多只有 logm 个。根据这个结论,只要对于每个位置预处理它后面第一个 highbit(aj) 大于某个位的位置 j,即可将对满足 r>k 的右端点 r 的枚举优化到 O(nlog2m) 的复杂度。

然后考虑 rk 的情况,直接暴力做复杂度就是对的,别的题解里都有这部分的证明,我就不再赘述。

时空复杂度均为 O(nlog2m),代码见下:

#include<bits/stdc++.h>
using namespace std;
#define re register
typedef double db;
typedef long long ll;
inline int win(){
	int x=0,w=0;char c=getchar();
	while(c>'9'||c<'0') w|=c=='-',c=getchar();
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return w?-x:x;
}

const int N=202020;
int p[N][31];ll a[N],s[N];

signed main(){
	int n=win(),ans=0;
	for(re int i=1;i<=n;++i) a[i]=win(),s[i]=a[i]+s[i-1];
	for(re int j=0;j<30;++j) p[n][j]=n+1;
	for(re int i=n,l;i>=1;--i){
		l=63-__builtin_clzll(a[i]);
		for(re int j=0;j<=l;++j) p[i-1][j]=i;
		for(re int j=l+1;j<30;++j) p[i-1][j]=p[i][j];
	}
	for(re int i=1,j,lmt;i<=n;++i){
		j=i+1,lmt=64-__builtin_clzll(a[i]);
		for(;j<n&&s[j]-s[i]<(1ll<<lmt);++j) if(s[j]-s[i]==(a[i]^a[j+1])) ++ans;
		if(j<n){
			lmt=63-__builtin_clzll(s[j]-s[i]),j=p[j][lmt];
			for(;j<=n&&lmt<=30;lmt=63-__builtin_clzll(s[j]-s[i]),j=p[j][lmt]) if((a[j]^a[i])==s[j-1]-s[i]) ++ans;
		}
	}
	printf("%d\n",ans);
	return 0;
}

posted @   WhaleAtCola  阅读(71)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示