Part 1:前置知识
1、状压 DP
2、基本的位运算操作
Part 2:SOS DP
(以下的内容大部分翻译至CF上的原文 )
1、例题引入
给定一个含 2 N 2^N 2N 个整数的集合 A A A,我们需要计算: ∀ x ⊆ A \forall x \subseteq A ∀x⊆A, x x x 中所有元素 i i i 的 A [ i ] A[i] A[i] 的和,即求:
F [ m a s k ] = ∑ i ⊆ m a s k A [ i ] F[mask]=\sum\limits_{i \subseteq mask}^{}{A[i}] F[mask]=i⊆mask∑A[i]
2、解题思路
法一:暴力枚举
-
我们可以枚举每一个 m a s k mask mask,再枚举集合中的所有元素 i i i,判断 i i i 是属于集合 m a s k mask mask。这样做的时间复杂度为 O ( 4 N ) O(4^N) O(4N)
-
代码
for(int mask=0; mask<(1<<N); mask++)
for(int i=0; i<(1<<N); i++)
if((mask&i)==i)
F[mask]+=A[i];
法二:枚举子集
-
对于任意 m a s k mask mask,如果它做的二进制位上有 k k k 个 1 1 1,那么它就有 2 k 2^k 2k 个子集,我们只需遍历这些子集便可。
时间复杂度为 O ( ∑ k = 0 N ( N k ) 2 k ) = O ( ( 1 + 2 ) N ) = O ( 3 N ) O(\sum\limits_{k=0}^{N}{\tbinom{N}{k}2^k})=O((1+2)^N)=O(3^N)