bitset优化背包

题目:https://agc020.contest.atcoder.jp/tasks/agc020_c

回忆下一题,是零一背包,主要的做法就是凑出最接近sum/2的价值,然后发现现在的背包的容量是2000*2000,物品数量是2000,那么如果你用正常的

数组背包的做法的话,8*10^9的复杂度是会超时的,代码如下:

int n;
    scanf("%d",&n);
    ll sum = 0;
    rep(i,0,n) scanf("%lld",&a[i]),sum+=a[i];
    dp[0] = 1;
    rep(i,0,n) repd(j,(sum+1)/2,a[i]) dp[j] = max(dp[j],dp[j-a[i]]);
    repd(i,sum/2,0) if(dp[i]) return printf("%lld",sum-i),0;
    return 0;

我们会发现,每个背包的状态要么是零,要么是1,那么我们就可以用bitset来实现速度上的优化:

8*10^9/64,那么这样的话,是符合时间限制的,代码如下:

bitset<maxn> bt;
int main()
{
    int n,a,sum = 0;
    scanf("%d",&n);
    bt[0] = 1;
    rep(i,0,n){
        scanf("%d",&a);
        bt |= bt<<a;
        sum += a;
    }
    rep(j,(sum+1)/2,sum+1) if(bt[j]) return printf("%d",j),0;
    return 0;
}

 那么为什么可以用位运算的|(或)呢,因为你看正常的数组做法,

dp[j] = max(dp[j],dp[j-a[i]]);

dpj是从dpj-ai转移过来的,所以减去ai就可以相当于位运算的左移

转载于:https://www.cnblogs.com/chinacwj/p/8371578.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值