《SOS高位前缀和》随便学学
前言:瘟疫席卷了全世界,就在快要统治人类的时候,因为不会 \(SOS\) 高维前缀和,导致传播速度是 \(O(3^n)\) ,而不是 \(O(2^nn^2)\) 导致速度过慢,被人类铲除。
\(ce\) ,模拟赛考了,赶紧恶补一下,自从 \(n\) 年前学完之后就忘了。
\(Part\ 1\) 引入
我们一般求一维前缀和就是直接加起来。
而对于二维前缀和就是 \(f_{i,j}=f_{i-1,j}+f_{i,j-1}-f_{i-1,j-1}\) ,进行容斥。
可当维数很高的时候就不行。
有一类题目要维护高维前缀和,可每个维度只有 \(0/1\) ,我们就可以考虑状压。
如果直接状压枚举子集不仅会算重需要容斥,而且复杂度 \(O(3^n)\) ,比较慢,我们考虑引入 \(Sum\ over\ Subsets\ dp\) 简称 \(SoSdp\)
具体如何操作,就以维护子集和为例。
我们按照维度来维护前缀和,先把第一维解决,第二维解决 \(\dots\) 以此类推。
就是说对于 \(j\) 来说。
如果 \(i\) 维是 \(1\) ,那么就加上 \(j\oplus 2^i\) 的前缀和,然后就没了。
点击查看代码
for(int i=1;i<=n;++i) {
for(int j=0;j<(1<<n);++j) {
if((j&(1<<(i-1)))) {
f[j]=(f[j]+f[j^(1<<(i-1))]);
}
}
}
非常简单。
具体的还可以完成后缀和以及高维差分等操作。
后缀和
点击查看代码
for(int i=1;i<=n;++i) {
for(int j=(1<<n)-1;j>=0;--j) {
if(!(j&(1<<(i-1)))) {
f[j]=(f[j]+f[j^(1<<(i-1))]);
}
}
}
差分(差分和前缀和是逆运算)
点击查看代码
for(int i=1;i<=n;++i) {
for(int j=0;j<(1<<n);++j) {
if((j&(1<<(i-1)))) {
f[j]=(f[j]-f[j^(1<<(i-1))]);
}
}
}
\(Part\ 2\) 实战演练
至于典题也比较水,就挂一个链接。
[ARC100E] Or Plus Max
Bits And Pieces
Compatible Numbers
Vowels
\(Part\ 3\) 写在最后
参考文献

浙公网安备 33010602011771号