题解:
首先考虑三维前缀和
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; }