加载中...

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\) 判断中的 ! 去掉即可。

code

posted @ 2025-07-19 11:00  jxs123  阅读(39)  评论(0)    收藏  举报