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)\) 的了。

浙公网安备 33010602011771号