思路:
① 观察到数据中,w仅有123
②暴力枚举所有选择重量为3的情况,那么剩余背包容积为M=m-3*i
③假设有w=2的x个,w=1的y个。2x+3y<=M,求max(sum[2][x]+sum[1][(M-2x)/3])
④很明显,一旦x确定,y的最大值也可以确定。很明显存在最大值(等待证明),凸字型三分求最值。
#include <bits/stdc++.h>
#define bug cout <<"bug"<<endl
using namespace std;
typedef long long ll;
const int MAX_N=1e5+3;
const int MOD=1e9+7;
vector <int> p[4];
ll sum[4][MAX_N];
ll n,m;
ll check(int n3,int n2){
int n1=m-3*n3-2*n2;
return sum[2][n2]+sum[1][min(n1,(int)p[1].size())];
}
int main(void){
cin >> n>>m;
for(int i=1;i<=n;i++){
int num,temp;
scanf("%d%d",&num,&temp);
p[num].push_back(temp);
}
for(int i=1;i<=3;i++){
sort(p[i].begin(),p[i].end(),greater<int>());
for(int j=0;j<(int)p[i].size();j++){
sum[i][j+1]=sum[i][j]+p[i][j];
// cout << sum[i][j+1]<<endl;
}
}
int cnt=min((ll)p[3].size(),m/3);
ll ans=0;
for(int i=0;i<=cnt;i++){
int l=0,r=min((ll)p[2].size(),(m-3*i)/2);
while(r>l+1){
ll midl=(l+r)>>1;
ll midr=(midl+r)>>1;
if(check(i,midl)>check(i,midr)) r=midr;
else l=midl;
// printf("midl=%d midr=%d\n",l,r);
}
ans=max(ans,max(check(i,l),check(i,r))+sum[3][i]);//check单调的情况
}
cout << ans << endl;
}