题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5119
题目大意:给定n个数字(范围在10^6之内),给定一个m;求在这n个数字当中取出任意的数字并求异或和,值需要大于等于m的组合一共有多少种。
解析:
首先,利用动态规划的方法,首先定义 dp[i][j] 为取到第 i 个数字时其异或和为 j 的可能的取法的种数;那么状态转移方程变为 dp[i][j] = dp[i-1][j] + dp[i-1][j^arr[i]] ; 在第 i 个数字的时候考虑其能达到异或和为 j 的可能性为: 1、不取第 i 个数字, 异或和为 j 的可能性为 dp[i-1][j]。2、取第 i 个数字, 异或和为 j 的可能性为dp[i-1][j^arr[i]]。
其次,初始时, 应将dp[0][0]初始化为1。由于n个数字中可能最大的数为1000000,在二进制下为1111 0100 0010 0100 0000 即:可能得到的最大的异或值为 1111 1111 1111 1111 1111 (十进制下)1048575。
知识点: 二进制异或运算的性质:
1、相同取0, 不同取1。
2、 a ^ b ^ a = b 即: arr[i]^x = j => arr[i]^j = x.
AC代码如下:
#include <iostream>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <string.h>
#include <sstream>
#include <cctype>
#include <climits>
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <vector>
#include <iterator>
#include <algorithm>
#include <stack>
#include <functional>
//cout << "OK" << endl;
#define _clr(x,y) memset(x,y,sizeof(x))
#define _inf(x) memset(x,0x3f,sizeof(x))
#define pb push_back
#define mp make_pair
#define FORD(i,a,b) for (int i=(a); i<=(b); i++)
#define FORP(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,n) for (int i=0; i<(n); i++)
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const double EULER = 0.577215664901532860;
const double PI = 3.1415926535897932384626;
const double E = 2.71828182845904523536028;
typedef long long LL;
LL pow_mod(LL a,LL n,LL m)
{
if(n == 0) return 1;
LL x = pow_mod(a,n>>1,m);
LL ans = x*x%m;
if(n&1) ans = ans*a%m;
return ans;
}
int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}
int arr[50];
LL dp[50][1048580];//1048580大于可能得到的最大的异或和的值 最大可能值为1048575
int main(){
int t;
cin >> t;
int cont = 1;
while(t--){
int n, m;
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
memset(arr,0,sizeof(arr));
for(int i = 1; i <= n; i++){
scanf("%d",&arr[i]);
}
dp[0][0] = 1;
for(int i = 1; i <= n; i++){
for(int j = 0; j < 1048576; j++){//注意这里dp的范围要在最大可能的范围之内
dp[i][j] = dp[i-1][j] + dp[i-1][j^arr[i]];
//cout << dp[i][j] << " ";
}
//cout << endl;
}
LL ans = 0;
for(int j = m; j < 1048576; j++){
ans += dp[n][j];
}
printf("Case #%d: %lld\n",cont++,ans);
}
return 0;
}