『容斥』51nod 1407 与与与与

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×(2fx1)

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值