zoukankan      html  css  js  c++  java
  • 2014年北京 happy matt friends(dp + 滚动数组优化)

    Happy Matt Friends

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


    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
     
    Recommend
    liuyiding
     
    这题比赛时候居然没有做出来呜呜呜,我对dp的学习路线让人怀疑。。。。
     
    接下来分析一下这个题
     
    本题大意:给定n个数,让你在n个数字中选择任意多个数字,使得他们的异或和 >= m。
    你不知道某些数字选还是不选,多选或者少选都可能多一种方案,看数据范围数字总共不到40个,
    最大值在1e6以内,所以这些值异或之后的最大值也不超过1 << 20,所以应该就要想到一个数字
    选还是不选应该是最重要的,他选了之后对于已经选过的值的影响的记录也是必要的,所以肯定要
    知道某个值选不选?然后还要把异或之后的值记录下来,记录的话肯定是需要一维记录了,我们想到可以把这些数可以异或得到的所有结果记录下来,然后查询大于等于m的个数有多少个即可。所以索性我们就假设dp[ i ][ j ]为前i个数,选择一些异或起来异或和为 j 的方案数,这样我们很容易就可以得到递推方程dp[ i ][ j ] = dp[i - 1][j ^ a[ i ]] + dp[i - 1][ j ],那就是一个数选或者不选,有两种情况,方法数相加。
     
    哦,一看就知道要开4 * 1e7的long long的数组,写出方程后应该可以想到数组是可以滚动的,因为
    对于每前i个的计算只需要前i - 1 个数的状态,所以我们索性就开一个dp[ 2 ][ maxn ]的数组,用 & 来滚动数组就行了。哦,具体见代码。
     
     1 /*
     2     本题思路:用dp[i][j]表示前i个数可以凑出数字j的方法数目。
     3     dp[i][j] = dp[i - 1][j ^ a[i]] + dp[i - 1][j];
     4 */
     5 #include <cstdio>
     6 #include <cstring>
     7 #include <algorithm>
     8 using namespace std;
     9 
    10 const int maxn = 40 + 5, maxm = 1 << 20;
    11 int n, m;
    12 
    13 typedef long long ll;
    14 
    15 int a[maxn];
    16 
    17 ll dp[2][maxm];
    18 
    19 int main() {
    20     int t, _case = 0;
    21     scanf("%d", &t);
    22     while(t --) {
    23         memset(dp, 0, sizeof dp);
    24         scanf("%d %d", &n, &m);
    25         for(int i = 1; i <= n; i ++) {
    26             scanf("%d", &a[i]);
    27         }
    28         /*
    29         dp[0][0] = 1;
    30         for(int i = 1; i <= n; i ++) {
    31             for(int j = 0; j < maxm; j ++) {
    32                 dp[i][j] = dp[i - 1][j ^ a[i]] + dp[i - 1][j];
    33             }
    34         }
    35         */
    36        dp[0][0] = 1;
    37        for(int i = 1; i <= n; i ++) {
    38            for(int j = 0; j < maxm; j ++) {
    39                dp[i & 1][j] = dp[i - 1 & 1][j ^ a[i]] + dp[i - 1 & 1][j]; 
    40            }
    41        }
    42         ll ans = 0;
    43         for(int i = m; i < maxm; i ++) {
    44             ans += dp[n & 1][i];
    45         }
    46         printf("Case #%d: %lld
    ", ++ _case, ans);
    47     }
    48     return 0;
    49 }
  • 相关阅读:
    Hive 中parse_url的使用
    作为首席架构师,我是如何选择并落地架构方案的?
    漫谈数据仓库之拉链表(原理、设计以及在Hive中的实现)
    纸上得来终觉浅
    年薪50万的大数据分析师养成记【摘抄】
    如果有人问你数据库的原理,叫他看这篇文章(完)
    开源大数据引擎:Greenplum 数据库架构分析
    【阿里在线技术峰会】李金波:企业大数据平台仓库架构建设思路
    ETL Automation完整安装方法_(元数据存放在mysql数据库)
    js定时器 离开当前页面任然执行的问题
  • 原文地址:https://www.cnblogs.com/bianjunting/p/11599201.html
Copyright © 2011-2022 走看看