http://acm.hdu.edu.cn/showproblem.php?pid=5119
题意:
给出n个数和一个上限m,求从这n个数里取任意个数做异或运算,最后的结果不小于m有多少种取法。
思路:
dp[i][j]表示在前i个数中取数做异或运算最后结果为j的方法数,那么dp[i][j] = dp[i-1][j] + dp[i-1][j^a[i]],分别对于取与不取这两种状态。
因为要推导出第i的状态只有i-1有关,所以这里可以用滚动数组。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn = (1<<20)+5; 7 8 long long n, m; 9 long long a[45]; 10 long long dp[2][maxn]; 11 12 int main() 13 { 14 //freopen("in.txt","r",stdin); 15 int T; 16 int kase = 0; 17 scanf("%d",&T); 18 while(T--) 19 { 20 scanf("%lld%lld",&n,&m); 21 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 22 memset(dp,0,sizeof(dp)); 23 dp[0][0] = 1; 24 for(int i=1;i<=n;i++) 25 { 26 for(long long j=0;j<maxn-5;j++) 27 { 28 dp[i%2][j] = dp[(i-1)%2][j] + dp[(i-1)%2][a[i]^j]; 29 } 30 } 31 long long ans = 0; 32 for(long long i=m;i<maxn-5;i++) ans += dp[n%2][i]; 33 printf("Case #%d: %lld ", ++kase, ans); 34 } 35 return 0; 36 }