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

    题解:

    首先考虑三维前缀和

    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];

    我们需要$2^t$来容斥

    但我们可以做到$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]=sum_{j in i }^{} f[j]$

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

    原理是一样的,可以把每一位数字看成一个维度,依次把第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

    题意:

    给出一些数字,问其选出一些数字作and为0的方案数有多少

    题解:

    发现直接求$and$起来等于$0$不太好进行

    于是我们转化为求$and$起来的数包含$k$

    这样就是我们要求包含k的数有几个,然后就是$2^num-1$

    这相当于求后缀和,我们把上面的枚举顺序倒一下就行了

    另外这样子求出来之后又要把后缀和转变为单点

    然后再差分一下

    感觉不是很好描述。。但是代码非常的easy

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (int i=h;i<=t;i++)
    #define dep(i,t,h) for (int i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    #define ll long long
    #define mep(x,y) memcpy(x,y,sizeof(y))
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T>void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f;
        }
        char sr[1<<24],z[20]; int Z,C=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C]=z[Z],--Z);
        }
        IL void wer1() { sr[++C]=' ';}
        IL void wer2() { sr[++C]='
    ';}
        template<class T>IL void maxa(T &x,T y) { if (x<y) x=y;} 
        template<class T>IL void mina(T &x,T y) { if (x>y) x=y;}
        template<class T>IL T MAX(T x,T y) {return x>y?x:y;}
        template<class T>IL T MIN(T x,T y) {return x<y?x:y;}
    };
    using namespace IO;
    const int N=1.1e6;
    int a[N],f[N],cj[N],n;
    const int mo=1e9+7;
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        read(n);
        rep(i,1,n) read(a[i]),f[a[i]]++;
        cj[0]=1;
        rep(i,1,1e6) cj[i]=cj[i-1]*2%mo;
        rep(i,1,20)
          dep(j,1e6,1)
            if ((j>>(i-1))&1) f[j^(1<<(i-1))]+=f[j];
        rep(i,1,1e6) f[i]=(cj[f[i]]-1)%mo;
        rep(i,1,20)
          dep(j,1e6,1)
            if ((j>>(i-1))&1) (f[j^(1<<(i-1))]-=f[j])%=mo;
        int ans=(cj[n]-1)%mo;
        rep(i,1,1e6) (ans-=f[i])%=mo;
        ans=(ans+mo)%mo;
        cout<<ans<<endl;
        return 0; 
    }
  • 相关阅读:
    遍历二维数组
    冒泡跟扫描共用
    1.8作业
    1.7作业
    1.5作业
    百文百鸡 水仙花数 百马百担
    for循环输出九九乘法表
    循环语句
    1.4作业
    07、找出1-99之间的同构数
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10107679.html
Copyright © 2011-2022 走看看