《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\) 写在最后

参考文献

月心绽放的末日的sosdp(高维前缀和)学习笔记

还有这篇文章

posted @ 2023-10-19 16:04  daduoli  阅读(26)  评论(0)    收藏  举报