高维前缀和

Posted miracevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高维前缀和相关的知识,希望对你有一定的参考价值。

我们经常要用到前缀和。

一维:

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

二维:

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

那如果是三维的呢?

for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        for(int k=1;k<=p;k++)
              b[i][j][k]=b[i-1][j][k]+b[i][j-1][k]+b[i][j][k-1]
                            -b[i-1][j-1][k]-b[i-1][j][k-1]-b[i][j-1][j-1]
                            +b[i-1][j-1][k-1]

其实就是一个容斥。

但是,随着维度t变高,容斥的复杂度是2^t,总复杂度O(n^t*2^t不能承受。

 

我们还有一个方法:

一维:

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

 

二维:

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

这个意思就是,第一遍前缀和,每个位置a[i][j]是,i行前j个的和。

第二遍,就把前面所有行的和加过来了。

分两遍达到目的。看似麻烦。

那三维呢?

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

其实和二维的理解是一样的。再来一遍,把第三维的和加过去。

 

但是,这个三维只要3次,也就是说,对于t维,其实只要O(n^t*t)复杂度就很低了。

 

其实我们实际解题中,经常用的是n=2的情况。

比如,

例题:

1.部分和(牛客网NOIP赛前集训营-普及组(第四场))

输入一个长度为n的数组a[i],下标从0开始(0到n-1)
保证n是2的整数次幂,
对于每个i (0 <= i < n)
求所有满足((i & j) == j)的a[j]之和。
n<=2^20
 
即,求每个i的子集和。
如果n=2^6,如果把i的二进制的表示:10101看做一个5维坐标的话,
那么,i的子集就是这个坐标的高维前缀和。
可以发现,每个维度的n都是2,
 
这就比较好处理了。
如果是一般的:w表示最高维度:
for(int i=0;i<w;i++){
    for(int j=0;j<(1<<w);j++){
        if(j&(1<<i)) f[j]+=f[j^(1<<w)]; 
    }
}

本题:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=(1<<21);
ll a[N];
int n;
int main(){
    scanf("%d",&n);int p=0;
    for(int i=0;i<n;i++) scanf("%lld",&a[i]);
    for(int i=1;i<n;i<<=1){p++;
        for(int j=0;j<n;j++){
            if((j&(1<<p-1))) a[j]+=a[(j^(1<<p-1))];
        }
    }for(int i=0;i<n;i++) printf("%lld
",a[i]);return 0;
}

 

 复杂度和高维前缀和一样;O(2^t*t)




以上是关于高维前缀和的主要内容,如果未能解决你的问题,请参考以下文章

高维前缀和

HDU5765 Bonds (高维前缀和)

高维前缀和

高维前缀和

高维前缀和

hihocoder1496(高维前缀和)