二进制分组背包。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,w; long long f[45][1050],x,y; int main() { while (scanf("%d%d",&n,&w)==2) { memset(f,0,sizeof(f)); if (n==-1 && w==-1) break; for (int i=1;i<=n;i++) { scanf("%lld%lld",&x,&y); int a,b=0; while (!(x&1)) {x>>=1;b++;} a=x; for (int j=1000;j>=a;j--) f[b][j]=max(f[b][j],f[b][j-a]+y); } for (int i=0;i<=30;i++) for (int j=1;j<=1000;j++) f[i][j]=max(f[i][j],f[i][j-1]); long long ans=0; for (int i=1;i<=1000;i++) ans=max(ans,f[0][i]); for (int i=1;i<=30 && (1<<i)<=w;i++) for (int j=min(1000,w>>i);j>=0;j--) for (int k=0;k<=j;k++) { f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(2*k+(((w>>(i-1))&1)>0),1000)]); ans=max(ans,f[i][j]); } printf("%lld\n",ans); } return 0; }