原题链接
知识点:DP, 二进制
将N个数看成二进制数,第i位看成2^(i - 1)
1.总和不大于M <== > N个二进制数中为1的权值的和 <= m
2.异或和为0 <==> 每一位都有偶数个1
f[i][j]:表示N个数的二进制的后i位的和
代码:
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 5010, M = 15, mod = 998244353;
int p[M], n, m;
LL f[M][N], fact[N], infact[N];
LL qmi(LL a, int b) {
LL res = 1;
while (b) {
if (b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
LL C(int a, int b) {
if (a < b || a < 0 || b < 0) return 0;
return fact[a] * infact[b] % mod * infact[a - b] % mod;
}
int main() {
p[0] = f[0][0] = 1;
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++) {
fact[i] = fact[i - 1] * i % mod;
infact[i] = infact[i - 1] * qmi(i, mod - 2) % mod;
}
for (int i = 1; i < M; i ++) {
p[i] = p[i - 1] * 2 % mod;
}
cin >> n >> m;
for (int i = 1; i < M; i ++) {
for (int j = 0; j <= m; j ++) {
int t = p[i - 1];
f[i][j] = f[i - 1][j];
for (int k = 2; j >= k * t && k <= n; k += 2) {
f[i][j] = (f[i][j] + f[i - 1][j - k * t] * C(n, k) % mod) % mod;
}
}
}
cout << f[M - 1][m] << endl;
return 0;
}