题目连接:Codeforces-808E - Selling Souvenirs
题意是一个背包问题,n和m都很大,但是物品重量在1和3之间
假设只有重量为2和3的两个物品,那么可以设置双指针来取,在O(n)的时间内可以解决。
那么我们分类讨论取重量为1物品的情况。如果我们取偶数个重量为1的物品,那么可以把重量为1的物品合成为重量为2的物品。
如果我们取奇数个重量为1的物品,那么先取出价值最大的那个物品,剩下的跟偶数情况一样处理就好了。
#include<bits/stdc++.h>
#define mp make_pair
#define pr pair<int,int>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N=1e5+7;
vector<ll> v1,v2,v3;
ll ans=0,res=0;
int n,m,ccc;
void solve()
{
int c=ccc;
int l,r;
for(l=(int)v2.size()-1;l>=0&&c+2<=m;l--) res+=v2[l],c+=2;
++l;
r=(int)v3.size()-1;
ans=max(ans,res);
while((l<v2.size()||v2.size()==0)&&r>=0)
{
res+=v3[r];c+=3;
while(c>m&&l<v2.size()) c-=2,res-=v2[l],++l;
if(c>m) break;
ans=max(ans,res);
--r;
}
}
int main()
{
cin>>n>>m;
int w;ll c;
for(int i=0;i<n;i++)
{
cin>>w>>c;
if(w==1) v1.push_back(c);
else if(w==2) v2.push_back(c);
else v3.push_back(c);
}
sort(v3.begin(),v3.end());
vector<ll> t2=v2;
sort(v1.begin(),v1.end());
for(int i=(int)v1.size()-1;i-1>=0;i-=2)
v2.push_back(v1[i]+v1[i-1]);
sort(v2.begin(),v2.end());
ccc=0;
solve();
v2=t2;
if(v1.size()) res=v1[v1.size()-1],ccc=1;
else res=0,ccc=0;
for(int i=(int)v1.size()-2;i-1>=0;i-=2)
v2.push_back(v1[i]+v1[i-1]);
sort(v2.begin(),v2.end());
solve();
cout << ans << endl;
return 0;
}