题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5119
题目来源:2014北京区域赛第三题。
简要题意:有一些值,求取一子集,异或和大于 M 的方案数。
题解
这是多年前我第二次区域赛,也是首铜时候写的题。
当时磨了很久,能做出来也是很开心的。
dp[i][j] 就是前 i 个朋友异或和为j 的方案,然后不断扫。可以开滚动或者是排序来优化,需要注意异或的上界不是 106 而是 220 。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
// head
const int M = 1<<20;
const int N = 45;
LL dp[2][M];
int a[N];
int main() {
int n, m, t, cas = 1;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", a+i);
}
sort(a, a+n);
dp[0][0] = 1;
int ub = 1;
int cur = 1, pre = 0;
for (int i = 0; i < n; i++) {
while (ub <= a[i]) ub <<= 1;
int x = a[i];
for (int j = 0; j < ub; j++) {
dp[cur][j] = dp[pre][j];
}
for (int j = 0; j < ub; j++) {
dp[cur][j^x] += dp[pre][j];
}
swap(cur, pre);
}
LL ans = 0;
for (int i = m; i < ub; i++) {
ans += dp[pre][i];
}
printf("Case #%d: %I64d\n", cas++, ans);
memset(dp, 0, sizeof dp);
}
return 0;
}