Educational Codeforces Round 61 (Rated for Div. 2) E. Knapsack 背包

62 篇文章 0 订阅

一道很神奇的背包题。

题目链接:http://codeforces.com/contest/1132/problem/E

 

题意:

        给你一个背包上限w和数字1-8的个数,注意w<=1e18,num[i]<=1e16。

 

 

似乎是一个巨大的背包,让我真的是,有点摸不到头脑啊。。想了一段时间也确实没想到,知道肯定是个背包就对了。。

做法:

       看了网上大佬的做法,很神奇,dp[i][j]表示for到数字i时能装到j的840的最大个数,因为840为1-8的最小公倍数,所以等于把所有的数字都处理到840以内,比如840/2=420,所以最后2剩下来用来背包的部分最多为419个,其他的都直接喂840了,然后就把这些数字用来背包,背包的上限就是840*8,也就是极限大家都差一点点的情况。

       具体的东西写在代码里。


#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
const int up=8*840;
typedef long long ll;
ll dp[10][maxn],a[10],w;
int main(){
    scanf("%lld",&w);
    for(int i=1;i<=8;i++) scanf("%lld",&a[i]);
    memset(dp,-1,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=8;i++){
        for(int j=0;j<=up;j++){
            if(dp[i-1][j]==-1) continue;
            ll most=min((ll)840/i,a[i]);
            //在需要最多i和i现在有多少里取一个上限
            for(int k=0;k<=most;k++){
                dp[i][j+k*i]=max(dp[i][j+k*i],dp[i-1][j]+(a[i]-k)/(840/i));
                //我不用来喂840的部分是给j的,其他的都用来喂840
            }
        }
    }
    ll ans=0;
    for(int i=0;i<=up;i++){
        if(i>w||dp[8][i]==-1) continue;
        ans=max(ans,i+840*min(dp[8][i],(w-i)/840));
        //在我能取到的最大数量和不会超过w里取一个最大值
    }
    printf("%lld\n",ans);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值