標籤:code bsp ++ 兩種 names \n 個人 col 一個
題目大意:有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 longint 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\n",ans1,ans2); continue; } sort(bx+1,bx+1+bc,cmp); ll ans3 = sy; ll ans4 = bx[1]; if(ans4>m) { printf("%I64d %I64d\n",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\n",ans1,ans2); else printf("%I64d %I64d\n",ans3,ans4); } return 0;}
HDU4415 Assassin’s Creed