Jzzhu and Numbers CodeForces - 449D (高维前缀和,容斥)
Posted uid001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jzzhu and Numbers CodeForces - 449D (高维前缀和,容斥)相关的知识,希望对你有一定的参考价值。
大意: 给定集合a, 求a的按位与和等于0的非空子集数.
首先由容斥可以得到 $ans = sum limits_{0le x <2^{20}} (-1)^{alpha} f_x$,
其中$alpha$为$x$二进制中$1$的个数, $f_x$表示与和等于$x$的非空子集数.
$f_x$是一个$20$维前缀和, 按传统容斥做法的话显然要超时, 可以每次求一维的和, 再累加
比方说对于2维前缀和, 用容斥的求法是这样
for (int i=1; i<=n; ++i) { for (int j=1; j<=n; ++j) { s[i][j] += s[i-1][j]+s[i][j-1]-s[i-1][j-1]; } }
优化后就是这样的
for (int i=1; i<=n; ++i) { for (int j=1; j<=m; ++j) { s[i][j] += s[i][j-1]; } } for (int j=1; j<=m; ++j) { for (int i=1; i<=n; ++i) { s[i][j] += s[i-1][j]; } }
本题的代码如下
#include <iostream> #include <algorithm> #include <cstdio> #define REP(i,a,n) for(int i=a;i<=n;++i) using namespace std; const int N = (1<<20)-1, P = 1e9+7; int n, a[N+10], pow2[N+10]; int main() { scanf("%d", &n); REP(i,1,n) { int t; scanf("%d", &t); ++a[t]; } pow2[0] = 1; REP(i,1,N) pow2[i]=pow2[i-1]*2%P; REP(j,0,19) REP(i,0,N) { if (i>>j&1) (a[i^(1<<j)]+=a[i])%=P; } int ans = 0; REP(i,0,N) { int sign = 1; for (int j=i; j; j^=j&-j) sign=-sign; (ans+=(sign*(pow2[a[i]]-1)+P)%P)%=P; } printf("%d ", ans); }
以上是关于Jzzhu and Numbers CodeForces - 449D (高维前缀和,容斥)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 449D:Jzzhu and Numbers(高维前缀和)
Jzzhu and Numbers CodeForces - 449D (容斥,dp)
CF449D Jzzhu and Numbers 高维前缀和
Jzzhu and Numbers CodeForces - 449D (高维前缀和,容斥)
CF449D Jzzhu and Numbers (状压DP+容斥)
Codeforces Round #257 (Div. 1) D - Jzzhu and Numbers 容斥原理 + SOS dp