// luogu-judger-enable-o2
/*
先求出f[i][j]代表只使用j*(2^i)的最大价值
再求f[i][j]代表使用小于等于j*(2^i)的所有物品
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
}
const int MAXN=200005;
int f[35][1150],w[35],n,m,len;
vector <int> G[35],V[35];
inline void Init(){
len=0;
memset(G,0,sizeof G);
memset(V,0,sizeof V);
memset(w,0,sizeof w);
memset(f,0,sizeof f);
}
int main(){
while(scanf("%d%d",&n,&m) && n!=-1){
Init();
for(int i=1;i<=n;i++){
int x=read();int j=0;
while(!(x&1)) x>>=1,j++;
G[j].push_back(x),w[j]+=x;
len=max(len,j);
int y=read();V[j].push_back(y);
}
for(int i=0;i<=len;i++)
for(int j=0;j<G[i].size();j++)
for(int k=w[i];k>=G[i][j];k--)
f[i][k]=max(f[i][k],f[i][k-G[i][j]]+V[i][j]);
//先求出f[i][j]代表只使用j*(2^i)的最大价值
while(m>>len) len++;len--;
//再求f[i][j]代表使用小于等于j*(2^i)的所有物品
for(int i=1;i<=len;i++){
w[i]+=(w[i-1]+1)/2;
for(int j=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( w[i-1], (k<<1)|(m>>(i-1)&1)) ]);
//把j*(2^i)拆成(j-k)*(2^i)和(k<<1)*(2^(i-1))进行转移
}
printf("%d\n",f[len][1]);//答案为f[len][1]:使用小于等于1*(2^len)的
}
}
转载于:https://www.cnblogs.com/lizehon/p/10630532.html