[bzoj1190]梦幻岛宝珠
根据$2^b$分组,组内处理出g[i][j]表示当容量为$j\cdot 2^{i}$且只能选b=i时最大价值,再组间dp用f[i][j]表示当容量为$j\cdot 2^{i}+(w\&(2^{i}-1))$且只能选$b<=i$时的最大价值(j的范围只有$\sum_{i=1}^{n}ai$,即使所有b都在一起也不会超过)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,a,b,v,g[35][1005],f[35][1005]; 4 int main(){ 5 while (scanf("%d%d",&n,&m)!=EOF){ 6 if ((n<0)&&(m<0))return 0; 7 memset(g,0,sizeof(g)); 8 memset(f,0,sizeof(f)); 9 for(int i=1;i<=n;i++){ 10 scanf("%d%d",&a,&v); 11 b=0; 12 while (a%2==0){ 13 a/=2; 14 b++; 15 } 16 for(int j=1000;j>=a;j--)g[b][j]=max(g[b][j],g[b][j-a]+v); 17 } 18 memcpy(f[0],g[0],sizeof(g[0])); 19 for(int i=1;i<=30;i++){ 20 int p=((m>>i-1)&1); 21 for(int j=1000;j>=0;j--) 22 for(int k=1000-p;k>=0;k-=2){ 23 int l=j+(k-p>>1); 24 if (l<=1000)f[i][l]=max(f[i][l],f[i-1][k]+g[i][j]); 25 } 26 } 27 printf("%d\n",f[30][0]); 28 } 29 }