专栏文章

CF449D Jzzhu and Numbers题解

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipduggv
此快照首次捕获于
2025/12/03 10:23
3 个月前
此快照最后确认于
2025/12/03 10:23
3 个月前
查看原文
ANDAND 表示若干个数 & 起来的结果。
xxyy 包含表示 x & y == y
直接设状态不好做。
于是转变思路。
hih_i 表示 ANDANDii 包含的所有 ANDAND 的方案数。
则答案可以由 hih_i 容斥得到。
由于只关心 hih_iii 在二进制下有几个 11 ,所以简化成代码中的 gig_i , 表示有 ii11
问题转化成如何求 hih_i 。 事实上只需求出 fif_i , 表示有多少个 axa_xii 包含。
hi=2fi1h_i = 2 ^ {f_i} - 1 。减一是因为要除去空集。
fif_i 显然可以 SOSdpSOSdp 求得。
代码如下 :
CPP
#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 20) + 100;
const int Mod = 1e9 + 7;
int n, res, a[N], f[N], g[N], _2[N];
inline void upd(int &x, int y) {
	x += y;
	if(x >= Mod) x -= Mod;
	if(x < 0) x += Mod;
	return;
}
signed main() {
	ios :: sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n;
	_2[0] = 1;
	for(int i = 1; i < (1 << 20); ++i) _2[i] = _2[i - 1] * 2 % Mod;
	for(int i = 1; i <= n; ++i) cin >> a[i], ++f[a[i]];
	for(int j = 0; j < 20; ++j)
		for(int i = (1 << 20) - 1; ~i; --i)
			if(i >> j & 1) upd(f[i ^ (1 << j)], f[i]);
	for(int i = 0; i < (1 << 20); ++i) upd(g[__builtin_popcount(i)], _2[f[i]] - 1);
	for(int i = 0; i < 20; ++i) {
		if(i & 1) upd(res, -g[i]);
		else upd(res, g[i]);
	}
	cout << res << '\n';
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...