高维前缀和
高维前缀和
高维前缀和,就是对每一个高维空间的点 \((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\)
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)]