洛谷 P7003
考虑当左端点固定时,区间的 & 和至多有 logw 种,因为 1 的数量是单调不升的。
所以我们可以枚举区间左端点 i,然后 ST 表预处理区间 & 和 + 二分求出一段 & 和相同的区间。
然后设 prei 表示原序列的前缀异或和,那么设当前这段 & 和相同的区间为 l,r,值为 x,那么就是要求 ∑rj=l[prej⊕prei−1=x],即 ∑rj=l[prej=prei−1⊕x],发现等式右边是个定值,那么就是求一段区间内一个数的出现次数,离散化后在 vector
里二分就好了。
时间复杂度 O(nlogwlogn)。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005, M = 17;
int n;
int f[N][M], lg[N];
int pre[N], _[N], tot;
vector <int> pos[N];
ll ans;
int query(int l, int r) {
int k = lg[r - l + 1];
return f[l][k] & f[r - (1 << k) + 1][k];
}
int main() {
scanf("%d", &n);
lg[0] = -1;
for (int i = 1; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
for (int i = 1; i <= n; ++i) scanf("%d", &f[i][0]), pre[i] = pre[i - 1] ^ f[i][0], _[++tot] = pre[i];
sort(_ + 1, _ + tot + 1), tot = unique(_ + 1, _ + tot + 1) - (_ + 1);
for (int i = 1; i <= n; ++i) pos[pre[i] = lower_bound(_ + 1, _ + tot + 1, pre[i]) - _].push_back(i);
for (int j = 1; j <= lg[n]; ++j)
for (int i = 1; i + (1 << j) - 1 <= n; ++i)
f[i][j] = f[i][j - 1] & f[i + (1 << (j - 1))][j - 1];
for (int i = 1; i <= n; ++i) {
for (int l = i, r = i; l <= n; l = r + 1) {
int L = l, R = n, val = query(i, l);
while (L < R) {
int mid = L + R + 1 >> 1;
if (query(i, mid) != val) R = mid - 1;
else L = mid;
}
r = L;
val ^= _[pre[i - 1]];
int p = lower_bound(_ + 1, _ + tot + 1, val) - _;
if (p <= tot && _[p] == val)
ans += upper_bound(pos[p].begin(), pos[p].end(), r) - lower_bound(pos[p].begin(), pos[p].end(), l);
}
}
printf("%lld", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具