- 高维前缀和 -
(瞎写,类似草稿)
高维前缀和一般解决这样的问题:
对于所有 \(0\le i\le 2^n-1\),求
\[\sum_{j\subset i}a_j \]其中 \(j\subset i\) 当且仅当 \(j\) 的二进制表示为 \(i\) 的二进制表示的子集 .
枚举子集(暴力)求的复杂度是 \(O(3^n)\) 的,但高维前缀和后就是 \(O(n2^n)\) 的了 .
先放代码:
for (int j=0;j<n;j++)
for (int i=0;i<1<<n;i++)
if (i>>j&1) a[i]+=a[i^(1<<j)];
原因:
先从二维前缀和说起 .
一般写的二维前缀和的预处理是这么写的:
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
但其实这种办法并不利于拓展,更好的写法是 逐维前缀和,如下:
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
a[i][j]+=a[i-1][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
a[i][j]+=a[i][j-1];
(这里直接在原数组进行是为了展示一致性)
类似的,高维前缀和均可这么做,例如 \(n\) 维前缀和可以这样:
for (int i1=1;i1<=n1;i1++)
for (int i2=1;i2<=n2;i2++)
...
for (int in=1;i1<=nn;in++)
a[i1][i2][...][in]+=a[i1+1][i2][...][in];
for (int i1=1;i1<=n1;i1++)
for (int i2=1;i2<=n2;i2++)
...
for (int in=1;i1<=nn;in++)
a[i1][i2][...][in]+=a[i1][i2+1][...][in];
... ...
for (int i1=1;i1<=n1;i1++)
for (int i2=1;i2<=n2;i2++)
...
for (int in=1;i1<=nn;in++)
a[i1][i2][...][in]+=a[i1][i2][...][in+1];
求解高维前缀和的核心思想也就是逐维处理,可以类比二维前缀和的求法稍微模拟一下 .
\[f_i\gets f_i+f_{i\oplus(1\mathrm{\, shl\,}j)}
\]
的写法也是因为 \(i\oplus(1\mathrm{\, shl\,}j)\) 是 \(i\) 的下一层 .
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/14987362.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ