[CF] CF900D Unusual Sequences
Description
Solution
若干位数\(\rm and\)起来\(=0\),可以容斥。即\((\ge0)-(\ge1)+(\ge2)-(\ge3)...\)(\(\ge{x}\)表示至少有\(x\)位为\(1\)的方案,即至少有\(x\)个不合法)
设\(ss[x](superset)\)表示二进制下\(x\)的超集中元素个数(超集中的\(y\)满足\(x\&y=x\),即如果\(x\)的某一位是\(1\),那么\(y\)的这一位也一定是\(1\),\(y\)可以\(=x\))
那么\(ss[j]+=ss[j+(1<<i)]((j\&(1<<i)=0))\)
\(x\)的超集有\(ss[x]\)个数,那么在里面任意选\(2^{ss[x]}-1\)个,它们的\(\&\)至少有\(popcount(x)\)个\(1\)
容斥即可。
Code
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int n, x, res, ss[1100005], f[25];
int read()
{
int x = 0, fl = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + ch - '0'; ch = getchar();}
return x * fl;
}
int qpow(int base, int pw)
{
int s = 1;
while (pw)
{
if (pw & 1) s = 1ll * s * base % mod;
base = 1ll * base * base % mod;
pw >>= 1;
}
return s;
}
int t1(int x)
{
int s = 0;
while (x)
{
s += (x & 1);
x >>= 1;
}
return s;
}
int main()
{
n = read();
for (int i = 1; i <= n; i ++ ) x = read(), ss[x] ++ ;
for (int i = 0; i <= 20; i ++ )
for (int j = 0; j <= (1 << 20) - 1; j ++ )
if ((j & (1 << i)) == 0 && (j + (1 << i) <= (1 << 20) - 1))
ss[j] = (ss[j] + ss[j + (1 << i)]) % mod;
for (int i = 0; i <= (1 << 20) - 1; i ++ ) f[t1(i)] = (f[t1(i)] + qpow(2, ss[i]) - 1) % mod;
for (int i = 0, o = 1; i <= 20; i ++ , o = -o) res = (res + 1ll * f[i] * o % mod + mod) % mod;
printf("%d\n", res);
return 0;
}