题目大意:有n个人,每个人有x,y两个值。x代表干掉他得到的分数,分数和不超过m;y代表干掉他后你能额外干掉多少个,且不计入总分。
求干掉人数最多为多少,以及最小的分。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
考试最后40分钟想出正解贪心,思路太乱没时间码导致20。
直接说正解:优雅的贪心
如果将y为0的放入a集,其余放入b集,那么正解只能有两种情况:
1.只从a中拿。
2.拿走全部的b,剩下将b从小到大排序后去掉最小,然后将b并入a中,再从a中拿。
为什么是这样的?
首先我们可以知道,只要拿走一个b,可以带出全部的b。
这样的话可以想象将bi建成一棵树:
b1->b2->b3
>b4->b5
>b6
假设它是一棵树
假设干掉b2要100块钱,还有一个a2要200块钱。
这样我们可以先干掉b2,花100,然后b1就少了一个儿子,在把a2放进去,就是:
b2->b3
b1->a2
>b4->b5
>b6
这样就是花100块钱干掉a2了。
我们还发现,b1是不能被置换的,因为它没有父亲。
所以正解:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100050 #define ll long long int T,n,ac,bc; ll ax[N],bx[N],by[N],m; bool cmp(ll x,ll y) { return x<y; } int cs; int main() { scanf("%d",&T); while(T--) { cs++; printf("Case %d: ",cs); scanf("%d%I64d",&n,&m); ll sy = 1; ac=bc=0; for(int i=1;i<=n;i++) { bc++; scanf("%I64d%I64d",&bx[bc],&by[bc]); if(!by[bc]) { ax[++ac]=bx[bc]; bc--; continue; } sy+=by[bc]; } sort(ax+1,ax+1+ac,cmp); ll ans1 = 0; ll ans2 = 0; for(int i=1;i<=ac;i++) { if(ans2+ax[i]<=m) { ans1++; ans2+=ax[i]; }else { break; } } if(!bc) { printf("%I64d %I64d ",ans1,ans2); continue; } sort(bx+1,bx+1+bc,cmp); ll ans3 = sy; ll ans4 = bx[1]; if(ans4>m) { printf("%I64d %I64d ",ans1,ans2); continue; } for(int i=2;i<=bc;i++) { ax[++ac] = bx[i]; } sort(ax+1,ax+1+ac,cmp); for(int i=1;i<=ac;i++) { if(ans3>=n) { ans3=n; break; } if(ans4+ax[i]<=m) { ans3++; ans4+=ax[i]; } } if(ans1>ans3||(ans1==ans3&&ans2<ans4))printf("%I64d %I64d ",ans1,ans2); else printf("%I64d %I64d ",ans3,ans4); } return 0; }