您的位置:首页 > 移动开发

HDU - 5119 Happy Matt Friends dp 滚动数组 异或和 (2014ACM/ICPC亚洲区北京站-重现赛(感谢北师和上交)

2017-09-20 10:37 567 查看
题目意思是:给定 n 个数,求所有子集的异或和 大于等于 m 的子集个数有多少

首先想到的是枚举子集,但是 n 最大是 40 ,2 的 40 次方没法实现

然而给定 的每个数 a [ i ] 最大范围是 1e6 ,二进制下不会超过 19 位,所以任意多个 a [ i ] 进行异或,其answer 都是小于 2进制下 20位的这个数 ------ (2 << 20)

然后开滚动数组 dp [ i ] [ j ] 表示前 i 个数中,异或和为 j 的个数

注意:题目中又说可以不选,所以初始化的时候 dp [ 1 ] [ 0 ] = 1; dp [ 1 ] [ a[i] ] = 1;

递推式就很容易了,见代码中:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <ctype.h>
#include <vector>
#include <algorithm>
#include <sstream>
#define PI acos(-1.0)
#define in freopen("in.txt", "r", stdin)
#define out freopen("out.txt", "w", stdout)
using namespace std;
typedef long long ll;
const int maxn = (1<<20) + 7, INF = 0x3f3f3f3f, mod = 1e9 + 7;
int T, n, m;
int a[50];
ll dp[42][maxn];

void init() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
memset(dp, 0, sizeof dp);
}

void solve() {
dp[1][0] = dp[1][a[1]] = 1;
for(int i = 1; i <= n; ++i) {
for(int j = 0; j < maxn; ++j) {
dp[i][j] += dp[i-1][j];
dp[i][j^a[i]] += dp[i-1][j];
}
}
ll ans = 0;
for(int i = m; i < maxn; ++i)
ans += dp
[i];
printf("%lld\n", ans);
}

int main() {
scanf("%d", &T);
int kase = 1;
while(T--) {
init();
printf("Case #%d: ", kase++);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: