[关闭]
@ysner 2018-11-04T22:10:29.000000Z 字数 1496 阅读 1937

[HNOI2007]梦幻岛宝珠

DP 背包


题面

给你颗宝石,每颗宝石都有重量和价值。要你从这些宝石中选取一些宝石,保证总重量不超过,且总价值最大。

解析

既然都告诉了重量是的幂次方带系数,那我们就可以用系数来代表一种重量。
就可以设状态为表示只取重量形如的物品,系数和小于等于的最大价值
(因为系数转移起点可以大于)。
然后可以在各个内跑背包。

接下来考虑合并不同的状态。
注意到一个问题,从小往大转移时,是会缩水的,因为会强制向下取整。

假定系列对系列的系数贡献为
此时,如果二进制中的第位为,说明对应的系列中的可以是。否则就只能是
这两个值后都是,但是

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;++i)
  11. #define fq(i,a,b) for(re int i=a;i>=b;--i)
  12. using namespace std;
  13. const int N=5e5+100;
  14. int n,m,f[35][1010],V[35][1010],mx,t[35],W[35][1010];
  15. il ll gi()
  16. {
  17. re ll x=0,t=1;
  18. re char ch=getchar();
  19. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  20. if(ch=='-') t=-1,ch=getchar();
  21. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  22. return x*t;
  23. }
  24. il int max(re int x,re int y){return x>y?x:y;}
  25. il void init()
  26. {
  27. mx=0;
  28. memset(f,0,sizeof(f));memset(V,0,sizeof(V));
  29. memset(W,0,sizeof(W));memset(t,0,sizeof(t));
  30. }
  31. int main()
  32. {
  33. while(233)
  34. {
  35. n=gi();m=gi();
  36. if(n==-1&&m==-1) break;
  37. init();
  38. fp(i,1,n)
  39. {
  40. re int x=gi(),y=gi(),j=0;
  41. while(!(x&1)) {x>>=1;++j;}
  42. mx=max(mx,j);
  43. t[j]+=x;
  44. V[j][++V[j][0]]=x;//volume
  45. W[j][++W[j][0]]=y;//val
  46. }
  47. fp(i,0,mx)
  48. fp(j,1,V[i][0])
  49. fq(k,t[i],V[i][j])
  50. f[i][k]=max(f[i][k],f[i][k-V[i][j]]+W[i][j]);
  51. while(m>>mx) ++mx;--mx;
  52. fp(i,1,mx)
  53. {
  54. t[i]+=(t[i-1]+1)/2;
  55. fq(j,t[i],0)
  56. fp(k,0,j)
  57. f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(t[i-1],(k<<1)|((m>>i-1)&1))]);
  58. }
  59. printf("%d\n",f[mx][1]);
  60. }
  61. return 0;
  62. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注