把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

浅谈高维前缀和

前言

高维前缀和听起来是个很高级的东西,其实也挺简单的。

应该说,它就是利用了状压的思想吧。

朴素算法

考虑朴素情况下,要求一个\(k\)维前缀和该怎么做?

\(k\)维数组啊。

比如当\(k=1\)时,我们会这么写:

for(int i=1;i<=n;++i) s[i]+=s[i-1];

又比如\(k=2\)时,我们会这么写:

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

(当然,\(k=2\)时还有容斥写法,这里就不说了,因为在扩展到高维后容斥会爆炸。)

于是,我们就发现,以\(s_{i,j}\)为例,其实每次就相当于枚举某一维,然后将它加上这一维减\(1\)位置上\(s\)的值,即\(s_{i,j-1}\)或者\(s_{i-1,j}\)

高维前缀和

考虑一下状压,例如对于一个三维前缀和\(s_{i,j,k}\)\(0\le i,j,k<p\),那么我们就可以把它压成\(s_{ip^2+jp+k}\)

然后我们同样枚举每一维,其实就是枚举一个\(p^x(0\le x<3)\),然后在\(0\sim p^3-1\)范围内枚举\(s_i\),若\(i\)\(x\)维上值大于\(0\),我们就可以将它加上\(s_{i-p^x}\)

这个思路应该是比较简单的吧。

代码

for(int k=1;k<=n;k*=p) for(int i=0;i<=n;++i) (i/k)%p&&(s[i]+=s[i-k]);//模板
posted @ 2019-08-16 07:20  TheLostWeak  阅读(817)  评论(0编辑  收藏  举报