DP - 01背包 - Happy Matt Friends - HDU - 5119

DP - 01背包 - Happy Matt Friends - HDU - 5119

题意:

T 组 测 试 用 例 , 每 组 包 括 整 数 n 和 m , 以 及 一 个 长 度 为 n 的 序 列 a i 。 T组测试用例,每组包括整数n和m,以及一个长度为n的序列a_i。 Tnmnai

在 这 n 个 数 中 选 择 一 些 数 , 使 得 这 些 数 的 异 或 值 大 于 等 于 m , 问 一 共 有 多 少 种 方 案 。 在这n个数中选择一些数,使得这些数的异或值大于等于m,问一共有多少种方案。 n使m

Sample Input:
2
3 2
1 2 3
3 3
1 2 3

Sample Output:
Case #1: 4
Case #2: 2

数据范围:

n < = 40 , m < = 1 0 6 , a i < = 1 0 6 。 T i m e   l i m i t : 6000 m s , M e m o r y   l i m i t : 510000 k B n<=40,m<=10^6,a_i<=10^6。\\Time\ limit:6000 ms,Memory \ limit:510000 kB n<=40m<=106ai<=106Time limit6000msMemory limit510000kB


分析:

一 个 比 较 明 显 的 01 背 包 问 题 , 只 是 把 体 积 限 制 改 成 了 异 或 值 的 大 小 。 一个比较明显的01背包问题,只是把体积限制改成了异或值的大小。 01

状 态 表 示 , f [ i ] [ j ] : 考 虑 前 i 个 数 , 且 异 或 值 不 超 过 j 的 方 案 总 数 。 状态表示,f[i][j]:考虑前i个数,且异或值不超过j的方案总数。 f[i][j]ij

状 态 计 算 : ① 、 不 包 含 第 i 个 数 : f [ i ] [ j ] = f [ i − 1 ] [ j ] 。 ② 、 包 含 第 i 个 数 : f [ i ] [ j ] = f [ i − 1 ] [ j 状态计算:\\①、不包含第i个数:f[i][j]=f[i-1][j]。\\②、包含第i个数:f[i][j]=f[i-1][j if[i][j]=f[i1][j]if[i][j]=f[i1][j^ a [ i ] ] 。 ( 这 由 异 或 的 性 质 容 易 得 到 ) 。 a[i]]。(这由异或的性质容易得到)。 a[i]]()
那 么 总 的 方 案 就 是 二 者 相 加 : f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j 那么总的方案就是二者相加:f[i][j]=f[i-1][j]+f[i-1][j f[i][j]=f[i1][j]+f[i1][j^ a [ i ] ] 。 a[i]]。 a[i]]

注意:

① 、 因 为 序 列 中 的 元 素 上 限 为 1 0 6 , 二 进 制 形 式 下 有 21 位 , 因 此 在 异 或 的 情 况 下 可 能 会 达 到 2 20 , 第 二 维 空 间 应 当 大 于 这 个 值 。 ①、因为序列中的元素上限为10^6,二进制形式下有21位,因此在异或的情况下可能会达到2^{20},\\\qquad第二维空间应当大于这个值。 10621220

② 、 第 二 层 循 环 应 当 要 枚 举 到 第 二 维 的 上 限 , 因 为 我 们 的 状 态 定 义 的 是 不 超 过 j , 最 后 要 求 的 应 当 是 ∑ i = m 2 20 f [ n ] [ i ] 。 ②、第二层循环应当要枚举到第二维的上限,因为我们的状态定义的是不超过j,最后要求的应当是\sum_{i=m}^{2^{20}}f[n][i]。 ji=m220f[n][i]

③ 、 f 数 组 应 当 开 l l 类 型 , 否 则 会 爆 i n t 。 ③、f数组应当开ll类型,否则会爆int。 fllint

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>

#define ll long long

using namespace std;

const int N=50,M=1<<20;

int T,n,m,a[N];
ll f[N][M];


int main()
{
    cin>>T;
    for(int t=1;t<=T;t++)
    {
        memset(f,0,sizeof f);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);

        f[0][0]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<M;j++)
                f[i][j]=f[i-1][j]+f[i-1][j^a[i]];

        ll res=0;
        for(int i=m;i<M;i++) res+=f[n][i];
        printf("Case #%d: %lld\n",t,res);
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值