Hduoj5199【DP】

/*Happy Matt Friends
Time Limit: 6000/6000 MS (Java/Others)    Memory Limit: 510000/510000 K (Java/Others)
Total Submission(s): 970    Accepted Submission(s): 390


Problem Description
Matt has N friends. They are playing a game together.

Each of Matt’s friends has a magic number. In the game, Matt selects some (could be zero) of his friends. If the xor 
(exclusive-or) sum of the selected friends’magic numbers is no less than M , Matt wins.

Matt wants to know the number of ways to win.
 
Input
The first line contains only one integer T , which indicates the number of test cases.

For each test case, the first line contains two integers N, M (1 ≤ N ≤ 40, 0 ≤ M ≤ 106).

In the second line, there are N integers ki (0 ≤ ki ≤ 106), indicating the i-th friend’s magic number.
 
Output
For each test case, output a single line “Case #x: y”, where x is the case number (starting from 1) and y indicates the 
number of ways where Matt can win.
 
Sample Input
2
3 2
1 2 3
3 3
1 2 3
 

Sample Output
Case #1: 4
Case #2: 2

HintIn the ?rst sample, Matt can win by selecting:
friend with number 1 and friend with number 2. The xor sum is 3.
friend with number 1 and friend with number 3. The xor sum is 2.
friend with number 2. The xor sum is 2.
friend with number 3. The xor sum is 3. Hence, the answer is 4.
 
Source
2014ACM/ICPC亚洲区北京站-重现赛(感谢北师和上交) 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  5338 5337 5336 5335 5334 
*/
#include<stdio.h>
#include<string.h>
int  n, m, a[44];
__int64 dp[2][1050010];//10的六次方进行异或运算不会超过2^20 
	
int main()
{
	int  t, cas = 1;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= n; ++i)
			scanf("%d", &a[i]);
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1;
		for(int i = 1; i <= n; ++i)
		{
			for(int j = 0; j < 1048576; ++j)
			dp[1][j] = dp[0][j];
			for(int j = 0; j < 1048576; ++j)
			{
				int k = j^a[i];
				dp[1][k] += dp[0][j];
			}
			for(int j = 0; j < 1048576; ++j)
			dp[0][j]  = dp[1][j]; 
		}
		__int64 k = 0;
		for(int i = m; i < 1048576; ++i)
		k += dp[1][i];
		printf("Case #%d: %I64d\n", cas++, k);
	}
	return 0;
} 

题意:给出n和m,然后再给出n个数,求其中有多少种组合能够使他们的异或和大于等于m。

思路:用DP的思想dp【i】【j】表示对于前i个数他们的异或和为j的方案数,那么dp【i+1】【j】就相当于是前一个的dp【i】【j】+dp【i】【某个j^第i+1个数】的方案数。

难点:这里有个很坑的细节问题就是输入的数保证在10^6之内,但是异或以后却有可能大于10^6,所以数组一定要比2^20大,否则就会发生访问非法内存了,其次就是最后的答案相加,题目要求的是比m大的数的方案全部要加起来,却没说上限,上限其实就是2^20,所以这个题最大的难点就在于这个上限了,要是没考虑到这一点,很难做对这一题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值