2025杭电多校1 1007(高维前缀和 | SOSdp)
1007
本题题解先略过,重点看求 \(dp[u][]\) 前缀和的部分:
auto s = dp[u];
for(int c = 0; c < m; c ++){
for(int state = 0; state < (1 << m); state ++){
if(!(state >> c & 1)){
s[state] += s[state ^ (1<<c)];
}
}
}
(\(m\) 为二进制位数,\(state\) 为二进制状态,\(dp\) 是一个二维数组:\(dp[u][state]\))
现在对 \(dp\) 数组的 \(state\) 这一维做前缀和,要求:
\[s[state] = \sum_{all\space state'} dp[state'], 其中state 为 state' 的子集
\]
可以用 \(O(m * 2^{m})\) 的复杂度获得 \(s\) 数组,如上述代码。具体证明可以自己手动模拟一下。
\(upd:\) 本来以为这是个 \(trick\),结果发现是 高维前缀和的一个特例 —— \(SOSdp\),(也称子集和 \(dp\)。可以看作维度为 \(m\),每一维长度为 \(2\) 的高维前缀和,\(s[0]\) 仅表示 \(a[0]\),\(s[1]\) 表示 \(a[0] + a[1]\))。学会的新知识点个数 ++。
那么反过来,如果要求:
\[s[state] = \sum_{all\space state'} dp[state'], 其中state' 为 state 的子集
\]
代码实现:
auto s = dp[u];
for(int c = 0; c < m; c ++){
for(int state = 0; state < (1 << m); state ++){
if(state >> c & 1){
s[state] += s[state ^ (1<<c)];
}
}
}
只需要将 \(if\) 判断中的 ! 去掉即可。

浙公网安备 33010602011771号