BZOJ1190_梦幻岛宝珠_KEY
观察数据a*2^b,转化成二进制后,后面跟了b位的0,可以转化为一个分层背包。
先预处理出每个物品是哪一层的,并放在同层内DP。
同层内直接背包,考虑层与层之间的DP。
第一维枚举层数,然后做类似于背包的DP,细节看code。
code:
/************************************************************** Problem: 1190 User: yekehe Language: C++ Result: Accepted Time:5932 ms Memory:960 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int read() { char c;while(c=getchar(),c!='-'&&(c<'0'||c>'9')); int x=0,y=1;c=='-'?y=-1:x=c-'0'; while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0'; return x*y; } int w[105],v[105],f[35][1005]; void work(int i)//预处理 { for(int k=0;k<=30;k++) if(w[i]&(1<<k)){ for(int j=1000;j>=(w[i]>>k);j--) f[k][j]=max(f[k][j-(w[i]>>k)]+v[i],f[k][j]); return ; } } int main() { while(1){ int N=read(),M=read(),ans=0; if(N<0&&M<0)break; memset(f,0,sizeof f); for(int i=1;i<=N;i++) w[i]=read(),v[i]=read(); for(int i=1;i<=N;i++)work(i); 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]); for(int i=1;i<=30&&1<<i<=M;i++){//枚举层数 for(int j=min(1000,M>>i);j>=0;j--){//枚举背包容量,类似01背包转移 for(int k=0;k<=j;k++){ f[i][j]=max(f[i][j],f[i-1][min((k<<1)+(M>>i-1&1),1000)]+f[i][j-k]);//k*2是因为从上一层转移。 ans=max(ans,f[i][j]); } } } printf("%d\n",ans); } return 0; }