【题解】CF1438E Yurii Can Do Everything
我的垃圾做法好像和别人有些不同,分享一下。
规定:记序列 表示序列 的前缀和, 表示数 的最高位,序列 值域为 。
首先考虑枚举一个端点找答案,不妨枚举 ,然后寻找枚举 的性质来减少枚举。
考虑左端点 ,不难发现对于一个 之后最小的位置 满足 , 之后的所有位置 若要作为右端点 ,因为 的第 位必然为 ,所以 必须满足 ,这时,对于 后的每一个位置 ,显然 大于 ,而 至多增大到 ,所以 后满足条件的右端点数量最多只有 个。根据这个结论,只要对于每个位置预处理它后面第一个 大于某个位的位置 ,即可将对满足 的右端点 的枚举优化到 的复杂度。
然后考虑 的情况,直接暴力做复杂度就是对的,别的题解里都有这部分的证明,我就不再赘述。
时空复杂度均为 ,代码见下:
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】