Loading

SOSDP 学习笔记

模板题:给定集合 \(S\),每次询问求 \(S\) 中在二进制下满足 \(x|k = k\)\(x\) 总和。

先介绍高维前缀和:在二维前缀和里,我们是这样计算的。

pre[i][j] = a[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];

这本质上是一种容斥。这样教的原因,是因为快速求矩阵和很方便。

但是当维度升高,这样做的复杂度指数级上升。

于是我们可以这样写:

for(int i = 1; i <= n; i ++)
	for(int j = 1; j <= m; j ++) pre[i][j] += pre[i - 1][j];
for(int i = 1; i <= n; i ++)
	for(int j = 1; j <= m; j ++) pre[i][j] += pre[i][j - 1];

复杂度是 \(\mathcal{O}(kV)\) 的,\(k\) 代表维数,\(V\) 代表总共的元素数,这里 \(=nm\)

回到问题,\(x|k = k\)\(x\) 就是二进制下属于 \(k\) 的数。我们把每一位看作一维,既然每一维都是 \(\le k\) 的,那么显然,所有满足条件的 \(x\),就是 \(k\) 二进制下的前缀和。

前缀和计算代码:

for(int i = 1, w = 1; i <= k; i ++, w <<= 1)//k 是维数,这里遍历每一维
	for(int j = 1; j <= mask; j ++)//这里遍历前缀和数组的每一个元素
		if(j & w) f[j] += f[j - w];//在这一维下进行前缀和运算

这样查询就是 \(\mathcal{O}(1)\) 的了。

posted @ 2026-07-23 14:20  Trent900  阅读(19)  评论(0)    收藏  举报