题目大意

给定 $n$ 个数,求出选 $k$ 数的异或和之和,模 $998244353$。

分析

对于每一二进制位,肯定只有异或值为 $1$ 才有贡献,那么就枚举这一位上取 $1$ 的个数为 $x$,那么取 $0$ 的个数对应地就为 $k-x$,这一位的贡献就为 $\binom{\text{count}(1)}{x}\cdot\binom{\text{count}(0)}{k-x}$。

代码

const int N = 1e5 + 10;
const int mod = 998244353;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, m;
ll a[N], mx;
ll qpow(ll a, int b) {
	ll ans = 1;
	for (; b; b >>= 1, a = a * a % mod)
		if (b & 1) ans = ans * a % mod;
	return ans;
}

ll prod[N], invp[N], ans;
ll C(int n, int m) {
	if (n < m) return 0;
	return prod[n] * invp[m] % mod * invp[n - m] % mod;
}

int main() {
	freopen("card.in", "r", stdin);
	freopen("card.out", "w", stdout);
	n = Read(), m = Read();
	for (int i = 1; i <= n; i++) a[i] = Read(), mx = max(a[i], mx);
	prod[0] = 1;
	for (int i = 1; i <= n; i++) prod[i] = prod[i - 1] * i % mod;
	invp[n] = qpow(prod[n], mod - 2);
	for (int i = n - 1; i >= 0; i--) invp[i] = invp[i + 1] * (i + 1) % mod;
	for (ll j = 1; j <= mx; j <<= 1) {
		int cnt0 = 0, cnt1 = 0;
		for (int i = 1; i <= n; i++)
			if (a[i] & j) cnt1++;
			else cnt0++;
		for (int i = max(m - cnt0 + ((m - cnt0) % 2 == 0), 1); i <= min(cnt1, m); i += 2) {
			(ans += C(cnt1, i) * C(cnt0, m - i) % mod * j % mod) %= mod;
		}
	}
	printf ("%lld\n", ans);
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2022-10-17 14:48:05
Tags