加载中...

高维前缀和 (SOSdp)

可以求解关于子集的前缀和,原理本质上是逐位前缀和。

int s[N];
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\) 为二进制状态,\(s[state]\) 需要初始化为集合 \(state\) 本身的函数值,进行上述算法后 \(s[state]\) 表示的是 \(state\) 的所有子集的函数值之和。)

\(dp\) 数组的 \(state\) 这一维做前缀和:

\[s[state] = \sum_{state'\subseteq state} dp[state'] \]

可以用 \(O(m * 2^{m})\) 的复杂度获得整个 \(s\) 数组。

辅助理解:可以将 \(n\) 位数字的每一位看作是一个维度,每个维度只有两种取值 \((0 和 1)\),其中 \(s[0] = a[0], s[1] = a[0] + a[1]\),上面的代码就是在做这样的前缀和过程。

反过来,如果要求:

\[s[state] = \sum_{state\subseteq state'} dp[state'] \]

int s[N];
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\) 判断中加上!。

原理见oi-wiki上的“逐维前缀和”部分:oi-wiki

posted @ 2025-07-19 11:00  小橘奏  阅读(61)  评论(0)    收藏  举报