http://acm.hdu.edu.cn/showproblem.php?pid=5119
dp[i][j]表示前i个数异或结果为j的方案数。
转移方程(这里的^是异或)
dp[i][j] = dp[i-1][j] + dp[i-1][j^k[i]]。
数组大小(这里的^表示幂)
因为2^19<10^6<2^20,也就是异或和用二进制表示最长为20位,最大值为2^20-1。
而每次状态更新都只与上一层有关,且答案只需要最后一层,所以只需要两层。
因此数组大小可设为dp[2][1<<20]。
思路
初始化dp[0][0]=1,所有的dp[i][j]写为dp[i%2][j],答案即为所有dp[n%2][j]之和,其中m<=j<=2^20-1。
注意点
方案总数会超过int范围,要用long long。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#define first fi
#define second se
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
//head
const int MAX = 1<<20;
LL dp[2][MAX];
int k[45];
int main()
{
int t;
scanf("%d",&t);
for(int tt=1; tt<=t; tt++)
{
int n,m;
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
scanf("%d",&k[i]);
dp[0][0] = 1;
for(int i=1; i<=n; i++)
{
for(int j=0; j<MAX; j++)
dp[i%2][j] = dp[(i-1)%2][j] + dp[(i-1)%2][j^k[i]];
// for(int j=0; j<MAX; j++)
// if(dp[i%2][j]!=0)
// printf("dp[%d][%d]%d ",i,j,dp[i%2][j]);
// printf("\n");
}
LL ans=0;
for(int j=m; j<MAX; j++)
{
ans += dp[n%2][j];
// if(dp[n%2][j]!=0)
// printf("ans += dp[n][%d]%d\n",j,dp[n%2][j]);
}
printf("Case #%d: %I64d\n",tt,ans);
}
}