本质: 前缀和问题(在布尔格上统计子集贡献)。

统计子集

子集的定义

SSTT 的子集,当且仅当 SS 中的所有元素都在 TT 中。

ST    iS,iT S \subseteq T \iff \forall i \in S, i \in T
  • 子集的个数: 2n2^n
  • 人话 : SS 只能由 TT 中的元素构成,且 SS 中的元素个数不超过 TT 中的元素个数。

SOS DP 的魔法在于:我们不一次性把所有位都变掉,而是一个比特一个比特地去允许变化。

我们定义状态 DP[i][mask]DP[i][mask]: 表示我们在计算 maskmask 的子集和,但是我们只允许子集的ii 个比特(第 00 位到第 ii 位)与 maskmask 不同(即可以是 00 也可以是 11),而剩余的比特(第 i+1i+1 位到 N1N-1 位)必须与 maskmask 严格保持一致

状态转移方程推导

考虑 DP[i][mask]DP[i][mask],我们需要看第 ii 个比特(假设是最低位为第 0 位):

  1. 情况 A:如果 maskmask 的第 ii 位是 00 那么它的子集在这一位上只能00。这意味着第 ii 位的变化权利被“浪费”了(因为它本来就被限制为 0,变不变都得是 0)。 所以,这等价于只允许前 i1i-1 位变化的情况:

    DP[i][mask]=DP[i1][mask]DP[i][mask] = DP[i-1][mask]

  2. 情况 B:如果 maskmask 的第 ii 位是 11 那么它的子集在这一位上可以是 00,也可以是 11。根据加法原理,我们将其拆分为两部分:

    • 00 的部分:这部分子集的第 ii 位固定为 00,其余高位与 maskmask 相同,低位(00i1i-1)随意。这正好对应 DP[i1][mask{2i}]DP[i-1][mask \setminus \{2^i\}](即把 maskmaskii 位变为 0 后的那个状态)。
    • 11 的部分:这部分子集的第 ii 位固定为 11,其余高位与 maskmask 相同,低位(00i1i-1)随意。这正好对应 DP[i1][mask]DP[i-1][mask]
    • 综上:
      DP[i][mask]=DP[i1][mask]+DP[i1][mask2i]DP[i][mask] = DP[i-1][mask] + DP[i-1][mask \oplus 2^i]

对应的题目: CF383E, CF165E

cpp
copy
        
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
vector<int> F(limit); for (int i = 0; i < limit; ++i) { cin >> F[i]; } // SOS DP 核心代码 // i 代表我们当前正在处理第 i 个比特位 for (int i = 0; i < n; ++i) { // 遍历所有的 mask for (int mask = 0; mask < limit; ++mask) { // 只有当 mask 的第 i 位是 1 时,才存在 "子集取 0" 和 "子集取 1" 的求和关系 // 如果 mask 第 i 位是 0,它只能取 0,值就是上一轮的值,无需操作 if (mask & (1 << i)) { // F[mask] 目前包含的是 "第 i 位取 1" 的子集和 (来自上一轮) // F[mask ^ (1 << i)] 包含的是 "第 i 位取 0" 的子集和 F[mask] += F[mask ^ (1 << i)]; } } } // 输出结果 // 此时 F[mask] 已经是 Sum over Subsets 了 for (int i = 0; i < limit; ++i) { cout << "Sum of subsets for mask " << i << ": " << F[i] << endl; }

统计超集

超集的定义

TTSS 的超集,当且仅当 SS 中的所有元素都在 TT 中。

TS    iS,iT T \supseteq S \iff \forall i \in S, i \in T
  • 人话 : TT 必须包含 SS 中的所有元素,且 TT 中的元素个数不小于 SS 中的元素个数。

我们定义状态 DP[i][mask]DP[i][mask]: 表示我们在计算 maskmask 的超集和,但是我们只允许子集的ii 个比特(第 00 位到第 ii 位)与 maskmask 不同(即可以是 00 也可以是 11),而剩余的比特(第 i+1i+1 位到 N1N-1 位)必须与 maskmask 严格保持一致

状态转移方程推导

考虑 DP[i][mask]DP[i][mask],我们需要看第 ii 个比特(假设是最低位为第 0 位):

  1. 情况 A:如果 maskmask 的第 ii 位是 11 那么它的超集在这一位上只能11。这意味着第 ii 位的变化权利被“浪费”了(超集的第 ii 位置 一定也是 11)。 所以,这等价于只允许前 i1i-1 位变化的情况:

    DP[i][mask]=DP[i1][mask]DP[i][mask] = DP[i-1][mask]

  2. 情况 B:如果 maskmask 的第 ii 位是 00 那么它的超集在这一位上可以是 00,也可以是 11。根据加法原理,我们将其拆分为两部分:

    • 00 的部分:这部分子集的第 ii 位固定为 00,其余高位与 maskmask 相同,低位(00i1i-1)随意。这正好对应 DP[i1][mask]DP[i-1][mask](即把 maskmaskii 位保持 0 后的那个状态)。
    • 11 的部分:这部分子集的第 ii 位固定为 11,其余高位与 maskmask 相同,低位(00i1i-1)随意。这正好对应 DP[i1][mask{2i}]DP[i-1][mask \cup \{2^i\}](即把 maskmaskii 位变成 1 后的那个状态)。
    • 综上:
      DP[i][mask]=DP[i1][mask]+DP[i1][mask2i]DP[i][mask] = DP[i-1][mask] + DP[i-1][mask \oplus 2^i]

举例子:

TODO

对应的题目: CF449D