题目中
wi=a∗2b
的提示太明显了吧。。
以这个为线索,跑裸的01会TLE,但是通过将相同的
b
归纳在一个
数组开小了WA了几次,找不到原因。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#define clr(x) memset((x),0,sizeof(x))
using namespace std;
inline void read(int &res){
static char ch;int flag=1;
while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;res=ch-48;
while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-48;res*=flag;
}
const int N=1005;
int val[N],w[N],sum[N],f[N][N],g[N][N],n,m,tot,dp[N][N];
int main(){
while(~scanf("%d%d",&n,&m)&&n!=-1&&m!=-1){
clr(w),clr(sum),clr(dp),clr(f),clr(g),clr(dp),tot=0;
for(register int x,y,i=1;i<=n;i++){
read(x),read(val[i]),y=0;
while(!(x&1))++y,x>>=1;
f[y][++sum[y]]=x;w[y]+=x;
tot=max(tot,y);g[y][sum[y]]=val[i];
}
for(register int i=0;i<=tot;++i)
for(register int j=1;j<=sum[i];++j)
for(register int k=w[i];k>=f[i][j];--k)
dp[i][k]=max(dp[i][k],dp[i][k-f[i][j]]+g[i][j]);
while(m>>tot)tot++;tot--;
for(register int i=1;i<=tot;++i){
w[i]+=(w[i-1]+1)>>1;
for(register int j=w[i];j>=0;--j)
for(register int k=0;k<=j;++k)
dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[i-1][min(w[i-1],(k<<1|(m>>(i-1))&1))]);
}
printf("%d\n",dp[tot][1]);
}
return 0;
}