这个题目,比赛的时候第一感觉就是贪心,但是一直没有找到办法贪心,写了100+行的代码也wa了,这是我见过的最牛b的贪心了; 比赛之后问了别人的思路,自己再细心的想想就想出来了,虽然别人跟我讲思路,我都没有听明白,T_T,貌似网上的代码很多就是错误的,我这个代码应该不会错,ac之后我把网上的数据都过了,自己还和别人对拍了随机数据,没问题……
分组1:b==0 的为一组
分组2: b!=0 为一组
结论:因为分组2,如果我们杀掉了其中一个,由于他们的武器都大于0,所以贪心的话肯定要把这组全部杀掉…… 故 组2要么一个不杀,要么都要杀掉
1. 组2一个不杀,那么组1从小到大开始杀,得到答案 cnt1 cost1
2. 组2都杀掉,问题都来了,组2用什么杀最好呢? 可以使用他们自己提供的武器 , 也可以消耗攻击值,如何贪心是这道题的难点。
谈谈我的思路: 首先我假设组2内除了开始消耗攻击值杀掉a最小的人外,其他的全部都用武器杀; 然后我们把剩下的武器杀掉那些组1内的a最大的人,接下来就得必须用攻击值了。 我 是用个 point 始终是指向 组1中还没有杀掉的a的最大的人,然后i从0 开始(即a由小到大)扫描,如果当前i指向的是组1的人,那么杀掉它肯定是最优的,小于i的都被傻掉了,再也没有a比i的a小了。 如果当前i指向的是组2的人,那么贪心的话肯定要用攻击值杀掉他,然后撤销之前用武器杀他,从而我们就获得了一个武器然后再贪心杀掉 point指向的人(point 始终指向的是 组1中没有被杀的a的最大的人)
实践证明: 测试数据没有出现讨论1的情况,也就是测试数据都是全部杀掉了组2中的人,数据确实弱了
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
#define pa system("pause")
const int maxn=100010;
const int inf=0x3fffffff;
struct node
{
int a,b;
}p[maxn];
int cmp(node c1,node c2)
{
return c1.a < c2.a;
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
int T,n,m,ca=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d%d",&p[i].a,&p[i].b);
sort(p,p+n,cmp);
int start=-1,cost1=0,cnt1=0,cost2=0,cnt2=0,weapon=0;
for(int i=0;i<n;i++)
if(p[i].b!=0)
{
cnt2++;
weapon+=p[i].b;
if(start==-1) start=i;
}else if(cost1+p[i].a<=m){
cost1+=p[i].a,cnt1++;
}
if(start==-1||m<p[start].a)
{
printf("Case %d: %d %d\n",ca++,cnt1,cost1);
continue;
}
int point=n-1;
weapon=weapon-cnt2+1;
cost2=p[start].a;
while(point>=0&&weapon>=0)
{
if(p[point].b==0)
{
if(weapon==0) break;
else cnt2++,weapon--;
}
point--;
}
for(int i=0;i<=point&&p[i].a+cost2<=m;i++)
if(i!=start)
{
cnt2++,cost2+=p[i].a;
if(p[i].b!=0)
{
point--;
while(point>=i&&p[point].b!=0) point--;
}
}
if(cnt1>cnt2||(cnt1==cnt2&&cost1<cost2)) printf("Case %d: %d %d\n",ca++,cnt1,cost1);
else printf("Case %d: %d %d\n",ca++,cnt2,cost2);
}
return 0;
}