zoukankan      html  css  js  c++  java
  • 高维前缀和

    高维前缀和

    一维:

    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

  • 相关阅读:
    URLEncode解决url中有特殊字符的问题
    监控系统概览
    SpringBoot 上传文件夹
    关于postgresql报 ERROR: XXX does not exist
    postgresql学习
    git学习
    学习博客
    面试准备
    jvm
    线程池面试题
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13573556.html
Copyright © 2011-2022 走看看