高维前缀和

高维前缀和

高维前缀和,就是对每一个高维空间的点 \((a_1,a_2,\cdots,a_k)\) ,求 \(\displaystyle \sum_{b_1=0}^{a_1} \sum_{b_2=0}^{a_2}\cdots \sum_{b_k=0}^{a_k} val(\overrightarrow{b})\)

一种做法是容斥,在此不详讲,复杂度 \(\mathcal O(n^k\cdot 2^k)\)

以二维为例:

for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
        sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];

另一种做法是降维。

考虑 \(\displaystyle f_i(\overrightarrow {a})=\sum_{b_1=0}^{a_1} \sum_{b_2=0}^{a_2}\cdots \sum_{b_i=0}^{a_i} val(b_1,b_2,\cdots ,b_i,a_{i+1},\cdots,a_k)\)

\(f_0(\overrightarrow{a})=val(\overrightarrow a),f_k(\overrightarrow a)=ans\)
考虑 \(f_{i-1}\rightarrow f_i\)

\(\displaystyle f_{i}(\overrightarrow a)=\sum_{b_i=0}^{a_i} f_{i-1}(a_1,a_2,\cdots,a_{i-1},b_i,a_{i+1},\cdots,a_k)\)

复杂度 \(\mathcal O(n^k\cdot k)\)

仍以二维为例:

for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
        sum[i][j]+=sum[i][j-1]+a[i][j];
for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
        sum[i][j]+=sum[i-1][j];

高维前缀差分

高维前缀和的逆运算,即已知 \(f_k(\overrightarrow a)\),求 \(\overrightarrow a\)

同样,只需考虑 \(f_{i-1}\leftarrow f_i\)

\[\begin{split} &f_{i}(\overrightarrow a)=\sum_{b_i=0}^{a_i} f_{i-1}(a_1,a_2,\cdots,a_{i-1},b_i,a_{i+1},\cdots,a_k) \\ \Rightarrow &f_{i-1}(\overrightarrow a)=f_i(a_1,a_2,\cdots,a_k)-f_i(a_1,a_2,\cdots,a_{i-1},a_i-1,\cdots,a_k) \end{split}\]

SOSDP

即求子集权值和。考虑到这等价于一个高维前缀和问题。

直接给出代码:

// f[s] 初始值为 val[s]
for(int i=0;i<k;++i)
    for(int s=0;s<(1<<k);++s)
        if(s&(1<<i)) f[s]+=f[s^(1<<i)]
posted @ 2023-01-09 08:32  pref_ctrl27  阅读(125)  评论(1编辑  收藏  举报