洛谷 P7003

考虑当左端点固定时,区间的 & 和至多有 logw 种,因为 1 的数量是单调不升的。

所以我们可以枚举区间左端点 i,然后 ST 表预处理区间 & 和 + 二分求出一段 & 和相同的区间。

然后设 prei 表示原序列的前缀异或和,那么设当前这段 & 和相同的区间为 l,r,值为 x,那么就是要求 rj=l[prejprei1=x],即 rj=l[prej=prei1x],发现等式右边是个定值,那么就是求一段区间内一个数的出现次数,离散化后在 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;
}
posted @   Kobe303  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示