高维前缀和

高维前缀和

一维:

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]+a[i][j][k];

其实就是一个容斥。

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

但我们可以做到 O(t)

其实就是我们先把行拼起来,再把列拼起来

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

另外一种一般是状压dp,(g[i]=∑_{j∈i}f[j])

这个东西暴力是$ O(3^n)$ 的,我们利用和上面同样的方法做到(O(2^nlogn))

原理是一样的,可以把每一位数字看成一个维度,依次把第i维拼起来

for(int i=0;i<w;i++)
    for(int j=0;j<(1<<w);j++)
        if(j&(1<<i)) 
            f[j]+=f[j^(1<<i)]; 

高维差分就是前缀和的逆过程,倒着做一遍就好了

codeforces 449D

没理解咕咕咕咕

若设 (f_s)表示 &之和 为 (f_s)的方案数

发现并不好处理,令 (f_s)表示子集含s的方案数,

那么实际上 (f_s)就是所有含s的集合的高维前缀和

倒着处理一遍所有含s的a的个数,那么显然是 (f_s=2^{num_s} -1)

然后差分回去就完了

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x;i <= y; ++ i)
#define repd(i,x,y) for(register int i = x;i >= y; -- i)
using namespace std;
typedef long long ll;
const int N = 2e6 + 50,mod = 1e9 + 7;
ll f[N];
int n,s;
inline int ksm(int x,int y)
{
    int ans = 1;
    while(y)
    {
        if(y&1) ans = 1ll * ans * x % mod;
        y >>= 1;x = 1ll * x * x % mod;
    }
    return ans;
}

inline void doit(int F)
{
    rep(i,0,19)
        repd(j,s,0)
            if((j&(1<<i))==0)
                f[j] = (f[j] + f[j|(1<<i)] * F %mod + mod)%mod;
}

int main()
{
    scanf("%d",&n); 
    rep(i,1,n) { int x;scanf("%d",&x); ++ f[x]; }
    s = (1 << 20) - 1;
    doit(1);
    rep(i,0,s) f[i] = ksm(2,f[i]) - 1;
    doit(-1);
    cout << f[0] << endl;
    return 0;
}

https://blog.csdn.net/qq_41955236/article/details/89301958

原文地址:https://www.cnblogs.com/ke-xin/p/13573556.html