1 条题解

  • 0
    @ 2026-6-5 12:57:04

    这个题目很有意思啊

    思路

    注意到这道题想让我们贪更多的满足度,我们就尝试贪心一下。

    首先,我们先把所有不用开罐器的罐头选上,自然是最省事的。但是这肯定不能满足我们的欲望,毕竟那么多需要开罐器的罐头我们还没有用过呢。那我们如果想要ii个需要开罐器的罐头,就必然需要选择一些开罐器,用二分就很好找到具体需要多少个开罐器。其实这题到这里就结束了。

    详细一点的解释看注释吧

    AC代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=2e5+10; 
    int a[N],b[N],c[N];
    signed main()
    {
    	int n,m;scanf("%lld%lld",&n,&m);
    	int A=0,B=0,C=0;
    	for(int i=1,t,x;i<=n;i++)
    	{
    		scanf("%lld%lld",&t,&x);
    		if(t==0)a[A++]=x;//开三个不同的数组存储 
    		if(t==1)b[B++]=x;
    		if(t==2)c[C++]=x;
    	}
    	sort(a,a+A,[](int x,int y){return x>y;});//排序一下,性能更好的物品我们更想要 
    	sort(b,b+B,[](int x,int y){return x>y;});
    	sort(c,c+C,[](int x,int y){return x>y;});
    	for(int i=1;i<=A;i++)a[i]+=a[i-1];//前缀和处理一下 
    	for(int i=1;i<=B;i++)b[i]+=b[i-1];
    	for(int i=1;i<=C;i++)c[i]+=c[i-1];
    	int ans=A==0?0:a[min(m-1,(int)A-1)];//不需要开罐器的罐头先有多少拿多少 
    	for(int i=0;i<B;i++)//选i个需要开罐器的罐头 
    	{
    		int l=0,r=C-1,res=-1;
    		while(l<=r)//二分 
    		{
    			int mid=l+r>>1;
    			if(c[mid]>=i+1)res=mid,r=mid-1;
    			else l=mid+1;
    		}
    		if(res==-1)continue;//开罐器不够 
    		int remain=m-(i+1)-(res+1);
    		if(remain>=0)
    			ans=max(ans,b[i]+(remain?a[min((int)A-1,remain-1)]:0));//更新答案 
    	}
    	printf("%lld\n",ans);
    	return 0;//完结撒花
    }
    
    • 1

    信息

    ID
    8888
    时间
    2000ms
    内存
    1024MiB
    难度
    6
    标签
    递交数
    39
    已通过
    12
    上传者