P r o b l e m \mathrm{Problem} Problem
S o l u t i o n \mathrm{Solution} Solution
这道题的方向不是 O ( n ) O(n) O(n),而是 O ( v ) O(v) O(v)。
我们发现答案为:全集 − a n d -\mathrm{and} −and有至少 1 1 1 位 0 0 0 的 + a n d +\mathrm{and} +and 后有至少 2 2 2 位 0 0 0 的…
因此我们可以根据一个数字 a n d \mathrm{and} and 操作后的位数来确定容斥系数。
考虑 a n d \mathrm{and} and 后位数至少 k k k 的答案,假设有 f x f_x fx个数的其中一个子集为 x x x,那么把这些数 a n d and and 以后,这些值至少为 x x x ,而这些方案恰好是至少有 c n t x cnt_x cntx位的贡献。
因此答案为: ∑ x ( − 1 ) c n t x × ( 2 f x − 1 ) \sum_{x} (-1)^{cnt_x}\times (2^{f_x}-1) x∑(−1)cntx×(2fx−1)
f
x
f_x
fx 的求解方法参考这篇精美博客哦!
C o d e \mathrm{Code} Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2100000;
const int P = 1e9 + 7;
int n;
int power[N], f[N], cnt[N];
int read(void)
{
int s = 0, w = 0; char c = getchar();
while (!isdigit(c)) w |= c == '-', c = getchar();
while (isdigit(c)) s = s*10+c-48, c = getchar();
return w ? -s : s;
}
void work(void)
{
int res = 0;
memset(f, 0, sizeof f);
for (int i=1;i<=n;++i) f[read()] ++;
for (int j=20;j>=0;--j)
for (int i=1e6;i>=0;--i)
if (((i >> j) & 1) == 0)
f[i] += f[i | 1 << j];
for (int i=0;i<=1e6;++i)
{
if (cnt[i] % 2 == 0) res = (res + (power[f[i]] - 1)) % P;
if (cnt[i] % 2 == 1) res = (res - (power[f[i]] - 1)) % P;
}
res = (res % P + P) % P;
cout << res << endl;
return;
}
signed main(void)
{
power[0] = 1;
for (int i=1;i<=1e6;++i) {
power[i] = power[i-1] * 2 % P;
cnt[i] = cnt[i >> 1] + (i & 1);
}
while (cin >> n) work();
return 0;
}