luogu CF449D Jzzhu and Numbers

luogu CF449D Jzzhu and Numbers
题目大意 求从 { a i } \{ ai \} {ai} 里面选出一个非空子集使这些数按位与起来为0的方案数
题解 方案数???
DP???
数据范围这么大??!!
不可做
考虑求问题的补集,and值不为0的有多少个
发现好像不是很好求
【luogu CF449D Jzzhu and Numbers】考虑DP
设f [ S ] 表 示 a n d 值 包 含 i 的 个 数 f[S]表示and值包含i的个数 f[S]表示and值包含i的个数
很容易发现f [ S ] = ∑ j = 0 20 f [ S ∣ ( 1 < < j ) ] f[S] = \sum\limits_{j=0}^{20}f[S | (1< 然后就可以十分愉快地DP出来啦(其实这叫做高位前缀和)
那怎么求不为0的方案数呢?
考虑容斥
按照二进制1出现的次数来容斥
然后这题就没了

#include #define int long long #define mod 1000000007 #define N 8000005 using namespace std; int qpow(long long x, int y){ long long ret = 1; for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod; return ret; } void fwt(int *a, int len, int opt){ for(int j = 0; j <= 20; j ++) for(int i = 0; i < len; i ++) if(!((1 << j) & i)) a[i] = (a[i] + opt * a[i | (1 << j)] + mod) % mod; } int pw[N], f[N], a[N], n; main(){ scanf("%lld", &n); for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]); for(int i = 1; i <= n; i ++) f[a[i]] ++; fwt(f, 1 << 20, 1); for(int i = 0; i < (1 << 20); i ++) f[i] = qpow(2, f[i]); long long ans = 0; for(int i = 0; i < (1 << 20); i ++){ int bit = 0; for(int j = 0; j <= 20; j ++)bit += (i >> j) & 1; if(bit & 1) ans -= f[i]; else ans += f[i]; ans = (ans + mod) % mod; } printf("%lld", ans); return 0; }

    推荐阅读