CF808E Selling Souvenirs

一、题目

点此看题

二、解法

复杂度允许枚举一类物品选取的个数,我们先枚举花费为 3 3 的物品个数。

剩余物品能选的最大价值是关于花费为 2 2 的选取物品个数 x x 呈单峰函数的,因为选少了可能更优,会增大,然后当选的比不选的更差时,就会下降,所以我们可以用三分解决这个问题。但是可能会有平台(函数值相等),但是平台只会出现在下降趋势,出现平台就往小的那边分治就可以了。

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int M = 200005;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,ans,res,v,s1[M],s2[M];
vector<int> a[4];
bool cmp(int x,int y)
{
	return x>y;
}
int cal(int x)
{
	if(2*x>v) return 0;
	int t=s2[x]+s1[min(v-2*x,(int)a[1].size())];
	res=max(res,t);
	return t;
}
void dich(int l,int r)
{
	if(l>r) return ;
	int m1=l+(r-l)/3,m2=r-(r-l)/3;
	int t1=cal(m1),t2=cal(m2);
	if(t1>=t2) dich(l,m2-1);
	else dich(m1+1,r);
}
signed main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		int w=read();
		a[w].push_back(read());
	}
	for(int i=1;i<=3;i++)
		sort(a[i].begin(),a[i].end(),cmp);
	for(int i=0;i<a[1].size();i++)
		s1[i+1]=s1[i]+a[1][i];
	for(int i=0;i<a[2].size();i++)
		s2[i+1]=s2[i]+a[2][i];
	res=0;v=m;
	dich(0,a[2].size());
	ans=res;
	for(int i=0,p=0;i<a[3].size();i++)
	{
		res=0;v=m-(i+1)*3;
		if(v<0) break;
		dich(0,a[2].size());
		p+=a[3][i];
		ans=max(ans,res+p);
	}
	printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/107548212