题解:AT_abc406_e [ABC406E] Popcount Sum 3
题解:AT_abc406_e [ABC406E] Popcount Sum 3
题意:求
首先考虑一个特殊情况,若没有
现实意义很简单,对于每个位
现在回到题目。加上了
我们记
考虑如何用已知的
首先,如果
求
实现方法有递归和递推,我觉得递归会好实现一些,__int128 无法 AC,欢迎 dalao 们指处错误。
#include <bits/stdc++.h>
using namespace std;
#define int unsigned long long int
const int mod = 998244353;
int qpow(int x, int y, const int mod) {
int res = 1;
for (; y; y >>= 1) {
if (y & 1) res = res * x % mod;
x = x * x % mod;
} return res;
}
int fac[65], invfac[65];
void init() {
fac[0] = 1; for (int i = 1; i <= 63; i++) fac[i] = fac[i - 1] * i % mod;
for (int i = 0; i <= 63; i++) invfac[i] = qpow(fac[i], mod - 2, mod);
}
int comb(int n, int m) { return m > n ? 0 : (__int128)fac[n] * invfac[m] % mod * invfac[n - m] % mod; }
int chose(int i, int j) { return (__int128)((1ULL << i) - 1) * comb(i - 1, j - 1) % mod; }
struct node { int sum, cnt; };
node solve(int n, int k, int t) { // t 记录的是当前位数
if (k > t + 1) return {0, 0};
else if (n == 0) return {0, !k};
if (n >> t) {
node x = solve(n ^ (1ULL << t), k - 1, t - 1);
return {(int)((chose(t, k) + x.sum) % mod + (__int128)x.cnt * (1ULL << t) % mod) % mod,
(x.cnt + comb(t, k)) % mod};
} else return solve(n, k, t - 1); // 还不是最高位
}
main() {
ios::sync_with_stdio(false), cin.tie(0);
init();
int t, n, k;
for (cin >> t; t; t--) {
cin >> n >> k;
int w = 63; while (!(n >> w & 1)) w--; // 求最高位
cout << solve(n, k, w).sum % mod << '\n';
}
return 0;
}