极大容量的完全背包问题

题目大意:

就是题目名称的意思,有n种物品,一个容量为m的背包,每种物品的体积为$ a_i $,价值为$ b_i $,有$ n<=10^6,m<=10^{18},a_i,b_i<=100 $。求最大价值。

解题方法:

因为m很大,所以我们考虑将较大的体积为S的背包分为较小的两个背包,其中一个体积为x,则另一个S-x。

这时讨论abs(x-(S-x))的范围,可以推出其<=maxv(物品的最大体积)。因为单独对两个背包操作,两边会有余留下来的部分,将其中一个余留下来的部分补到另一个去可能会得到更忧解。但如果移动的部分大于maxv了则放在两个背包中的任意一个都可以得到最优解。所以我们成功将枚举区间缩小到了$ frac{S-maxv} {2} <=x<= frac{S+maxv} {2} $。

然后我们类似分治的套路将图画出来:

发现$ Max -Min < 2 imes maxv $并且最底层(即$ Min>0 $的最后一层)的$ Min <= maxv,Max<=3 imes maxv $,所以我们可以预处理出$ 3 imes maxv $大小的背包就可以得到最底层的解,然后我们可以记录每层最小值$ L[i] $即最左边的点的权值,设$ g[i][j] $表示在第i层时比$ L[i] $容量大j的背包的最优解,枚举x逐层向上转移即可,转移方程:$ g[i][v-L[i]]=max(g[i+1][x-L[i+1]]+g[i+1][v-x-L[i+1]]) $。

因为一开始给了$ 10 ^ 6$种物品,然而因为最多有$ 100 imes 100 $种物品,所以可以用set去重。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define del(a,b) memset(a,b,sizeof(a))
 4 using namespace std;
 5 const int MAXN=1e5+10;
 6 ll n,m,tot;
 7 set<int> ap[110];
 8 ll f[MAXN],g[55][MAXN],L[55],a[MAXN],b[MAXN];
 9 void Max(ll &a,ll b){a=(a>b? a:b);}
10 template <class T>void read(T &x)
11 {
12     bool f=0;char ch=getchar();x=0;
13     for(;ch<'0' || ch>'9';ch=getchar())if(ch=='-') f=1;
14     for(;ch>='0' && ch<='9';ch=getchar())x=x*10+ch-'0';
15     if(f) x=-x;
16 }
17 int main()
18 {
19     read(n);read(m);
20     ll maxv=0;
21     for(int i=1;i<=n;i++)
22     {
23         ll x,y;read(x);read(y);
24         if(ap[x].find(y)!=ap[x].end()) continue;
25         a[++tot]=x;b[tot]=y;ap[x].insert(y);
26         Max(maxv,a[tot]);
27     }
28     ll s=m,cnt=0;
29     while(s>0)
30     {
31         L[++cnt]=s;
32         s=(s-maxv)>>1;
33     }
34     for(int i=1;i<=tot;i++)
35     for(int v=a[i];v<=maxv*3;v++)
36         Max(f[v],f[v-a[i]]+b[i]);
37     for(int i=cnt;i>=1;i--)
38     for(ll v=L[i];v<=L[i]+maxv*2;v++)
39     {
40         if(v<=maxv*3) g[i][v-L[i]]=f[v];
41         else
42         {
43             for(ll x=(v-maxv)>>1;x<=v>>1;x++)
44             Max(g[i][v-L[i]],g[i+1][x-L[i+1]]+g[i+1][v-x-L[i+1]]);
45         }
46     }
47     printf("%lld",g[1][0]);
48     return 0;
49 }
View Code
原文地址:https://www.cnblogs.com/Oracle-LinJH/p/9827067.html