Happy Matt Friends(利用滚动数组优化数组空间的DP)



Link:http://acm.hdu.edu.cn/showproblem.php?pid=5119



Happy Matt Friends

Time Limit: 6000/6000 MS (Java/Others)    Memory Limit: 510000/510000 K (Java/Others)
Total Submission(s): 1718    Accepted Submission(s): 681


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 ≤ 10 6).

In the second line, there are N integers ki (0 ≤ k i ≤ 10 6), 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
Hint
In the first 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
 


题意:n个数,可以取其中一部分来异或,问全部异或结果不小于m有多少种取法。


编程思想:dp(背包)。dp(i,j)表示取到第i个数,异或结果为j,有多少种方法。初态是有一种取法取得0,然后对每个数,有两种选择,取或不取,加上上一步的路径数就可以了。最后将dp(n,j)中j>=m的部分求和就行。需要注意的是,会爆int。分析由于n<=40&&m<=10^6,因此我们可以枚举所有可能的异或值,时间复杂度40*10^6。采用动态规划的思想,转态转移方程为:dp[i&1][j]=d[(i-1)&1][j]+d[(i-1)&1][j^a[i]];由于40*10^6太大,所以此处我们采用滚动数组。


AC code:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
#include<cmath>
#include<vector>
#include<string.h>
#define LL long long
using namespace std;
const int maxn=1<<20;
int dp[2][maxn];
int ki[44];

//dp[i&1][j]=dp[(i-1)&1][j]+dp[(i-1)&1][j^ki[i]];

LL ans;
int main()
{
    //freopen("D:\\in.txt","r",stdin);
    //printf("%lf\n",log(1000000.0)*1.0/log(2.0));
    int T,n,m,i,j,cas;
    scanf("%d",&T);
    for(cas=1;cas<=T;cas++)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&ki[i]);
        }
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(i=1;i<=n;i++)
        {
            for(j=0;j<maxn;j++)
            {
                dp[i&1][j]=dp[(i-1)&1][j]+dp[(i-1)&1][j^ki[i]];
            }
        }
        ans=0;
        i=n&1;
        for(j=m;j<maxn;j++)
        {
            ans+=dp[i][j];
        }
        printf("Case #%d: %I64d\n",cas,ans);
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林下的码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值