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

滴答滴答---题目链接 

Happy Matt Friends

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


 

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 ≤ 106).

In the second line, there are N integers ki (0 ≤ ki ≤ 106), 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

2014ACM/ICPC亚洲区北京站-重现赛(感谢北师和上交)

 

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  6447 6446 6445 6444 6443 

 

有一个bug:题目虽然告诉你数<10^6,也就是2^17,理论上来说异或和不会到2^18

但是你开到2^18就错了,还是开到20,其实19也行

 题意:
  matt有N个朋友,现在需要从中选出n个(0<=n<=N),使得每个朋友的ki值,异或结果(^)大于等于M。
思路:
  首先注意题目数据范围: N<=40   M<=10^6
  先排除暴力枚举的情况,
dp思路:
  与背包类似:  考虑第i+1个人,选或不选
  f[i][j]表示前i个人,选择其中k个(k<=i),使得异或结果为j。
  递推式:
    不选第i个人:  f[i+1][j] += f[i][j];   // 这里ans不进行累加,因为两种情况为同一种情况! 
    选择第i个人:  f[i+1][j^a[i]]  +=  f[i][j];此时,如果当前异或结果(j^a[i])>=M, 则加入最终ans中: ans += f[i][j];
 
·注意: 本题也可以全部计算出 f[i][j],使用双重循环,求sum{f[n][j](j>=m)},即为结果。

 

对  if(m==0) num++;  的理解:(个人理解,如果不对欢迎大家纠错!!)

  当m为0的时候,一个人都不选,可以为一种情况,加上这种情况。(当m不为0的时候,至少需要选择1个人。)

初始化 f[0][0] = 1; 的理解:

  前0个人,异或结果为0时,为一种情况,结果为1.(即上面提到的)

  同时这里因为双重for循环中每次加的都是f[i+1][j],所以不会计算重复!
 

#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N=1<<20;
int dp[64][N];
int a[45];
int main()
{
    int t;
    scanf("%d",&t);
    int f=0;
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i=m)ans+=dp[i][j];
                 //注意这里是增加的f[i][j] !!! 把每次累加的加入进来即可
            }
        f++;
        printf("Case #%d: %lld\n",f,ans);
    }

    return 0;
}

 

你可能感兴趣的:(VJ)