HDU 5119 Happy Matt Friends 2014ACM/ICPC亚洲区北京站

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wust_zzwh/article/details/48184831



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.
 题意:有n个数,从中选x个(x可以为0)进行xor(异或)运算得到一个值,问得到这个值大于等于M的选法有多少种?

 思路:  显然n个数选x个就是n个数的所有子集有2^n种,对于每个数a[ i ] 可以选或者不选,这就是背包模型嘛!

设dp[ i ] [ j ]表示选第i个数时已选的 i-1 个数的异或值为j的方案数,那么转移方程:

dp[i][j]+=dp[i-1][j](这是不选第i个数的情况,直接加上i-1个是j状态),

dp[ i ] [ j^a[i] ]+=dp[i-1][j](这是选a[i] 的情况);

不过背包体积不能简单的定为M,因为题目求的是异或值,选第i个数就要异或a[i],异或后的值不一定比异或前的小(也就是说一个数异或后可能变小),

所以dp要保存0到上限的所有值。

然后就是上限的问题,先把a[i]的最大值拿出来ma=max(a[i]),上限肯定跟ma有关系,假设ma的二进制表示为101001,然后用一个比它小的数(因为ma已经是最大的呢)跟它异或,得到结果的二进制最高位肯定不会比ma的高,仔细想想最高位的1怎么算都不会进位,而除了最高位,其他位都是可以任意变化的,也就是说异或的最大值就是111111

即ma的所有有效位为1;这个就是上限;初始状态就是方案数都为0,不过题目说可以选0个,那么dp[0][0]=1;

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1048575+5;
const int INF=0x3f3f3f3f;
typedef __int64 ll;
ll dp[44][maxn];
ll a[44];
ll get(int m)//计算上限
{
    int cnt=0;//记录有多少位
    while(m)
    {
        cnt++;
        m>>=1;
    }
    return ll(1<<cnt)-1;//全1
}
int main()
{
    int t;
    //cout<<get(1e6);预算最大值的上限
    scanf("%d",&t);
    int k=1;
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        ll ma=0;
        for(int i=1;i<=n;i++)
            scanf("%I64d",&a[i]),ma=max(ma,a[i]);
        ma=get(ma);
        memset(dp,0,sizeof dp);
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        for(ll j=0;j<=ma;j++){
            dp[i][j]+=dp[i-1][j];//不选
            dp[i][j^a[i]]+=dp[i-1][j];//选
        }
        ll ans=0;
        for(int i=m;i<=ma;i++)
            ans+=dp[n][i];
        printf("Case #%d: %I64d\n",k++,ans);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/wust_zzwh/article/details/48184831