高维前缀和

题解:

首先考虑三维前缀和

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; 
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/10107679.html