【纪中模拟2019.08.18】【JZOJ6309】完全背包

南笙酒味 提交于 2019-11-27 19:23:22

题目链接

 

题意:

  有$n$种物品各有无限个,背包空间为$m$,第$i$种物品的体积为$a_i$,价值为$b_i$。求在不超过背包容量的前提下,取得的最大价值。

  $n\le 10^6,\quad m\le 10^{16},\quad a_i,b_i\le 100$且均为正整数。

 

分析:

  贪心一:实际上最多有$100\times 100=10^4$种物品,可以考虑去重,这样$n$的规模下降至$10^4$。

  贪心二:如果两种物品的体积相同,我们肯定不会装价值更低的那种物品,这样$n$的规模下降至$100$。

  转化法:由于$m$过于巨大,然而$a_i$相比较小,我们可以想到,性价比最优的物品一定会出现极多次,这样最终方案肯定可以分割成很多完全相同的小方案(全部装同一种物品),再在剩下的容量里精打细算。因此我们先做小容量(最大可支持的范围)的背包,再来组成最终方案。

  综上,我们先做$n\le 100$,$m\le 2\times 10^5$的完全背包,设$f_i$表示背包容量为$i(1\le i \le 2\times 10^5)$时能取得的最大价值,则有$$f_m=\mathop{max}\limits_{i=1}^{2\times 10^5}\{\lfloor m/i \rfloor \times f_i + f_{m\%i}\}$$

 

实现(100分):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define IL inline
using namespace std;
typedef long long LL;
const int N=100;
const int M=2e4;

    int n;
    LL m,w[103];
    LL f[M+3];

int main(){
    freopen("backpack.in","r",stdin);
    freopen("backpack.out","w",stdout);

    scanf("%d%lld",&n,&m);
    memset(w,0,sizeof w);
    for(int i=1;i<=n;i++){
        LL x,y;
        scanf("%lld%lld",&x,&y);
        w[x]=max(w[x],y);
        
    }
    
    memset(f,0,sizeof f);
    for(int i=1;i<=N;i++)
        for(int j=i;j<=M;j++)
            f[j]=max(f[j],f[j-i]+w[i]);
    
    LL ans=0;
    for(int i=1;i<=M;i++)
        ans=max(ans,m/i*f[i]+f[m%i]);
    
    printf("%lld",ans);

    return 0;

}
View Code

 

小结:

  数据规模不同,造就不同题目。应学会灵活处理。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!