题意
你有一把耐久度为 m m m 的刀,每次杀一个敌人需要 a i a_i ai 的耐久度,同时得到一个能杀 b i b_i bi 个人的刀,问你最多能杀多少个敌人和最小的花费。
解题方法
可以讨论 b i b_i bi 是否大于0,我们考虑两种贪心策略,第一种是按 a i a_i ai 为关键字排序从小到大杀,第二种我们就是优先杀一个 b i > 0 b_i>0 bi>0的人,然后看看能不能杀全场,如果不能就从大到小杀,费耐久度的从小到大杀就可以了。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int a,b;
}p[200010];
int n,m;
int ans1,ans2,cost1,cost2;
bool comp(node x,node y)
{
return x.a<y.a;
}
void work1()
{
int ci=0;
int now=m;
int i;
for(i=1;i<=n;i++)
{
if(now-p[i].a>=0)
{
ans1+=0;
cost1+=p[i].a;
now-=p[i].a;
ci+=p[i].b;
}
else
{
break;
}
}
for(int j=i;j<=n;j++)
{
if(ci==0)break;
ans1++;
ci--;
ci+=p[j].b;
if(ci==0)break;
}
return;
}
bool vis[100005];
void work2()
{
int now=n+1;
for(int i=1;i<=n;i++)
if(p[i].b)
{
now=i;
break;
}
// cout<<now<<"#$%^#$"<<'\n';
if(now==n+1)return;
// puts("14124124");
if(p[now].a>m)return;
// puts("14124124");
int tot=0;
for(int i=1;i<=n;i++)
tot+=p[i].b;
// cout<<tot<<" "<<now<<"#$%^#$"<<'\n';
if(tot+1>=n)
{
ans2=n;
cost2=p[now].a;
return;
}
memset(vis,0,sizeof(vis));
vis[now]=1;
ans2=tot+1;
for(int i=n;i;i--)
{
if(!vis[i])
{
tot-=1;
vis[i]=1;
if(tot==0)
break;
}
}
cost2=p[now].a;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
if(m-cost2-p[i].a>=0)
{
cost2+=p[i].a;
ans2++;
}
else
{
break;
}
}
}
return;
}
int main()
{
int t;
scanf("%d",&t);
for(int ci=1;ci<=t;ci++)
{
scanf("%d%d",&n,&m);
ans1=ans2=cost1=cost2=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&p[i].a,&p[i].b);
}
sort(p+1,p+n+1,comp);
cout<<"Case "<<ci<<": ";
work1();
work2();
// cout<<ans1<<" "<<ans2<<" ";
if(ans1>ans2||(ans1==ans2&&cost1<cost2))
{
cout<<ans1<<" "<<cost1<<'\n';
}
else
{
cout<<ans2<<" "<<cost2<<'\n';
}
}
return 0;
}