题意
有 $n$ 种树,每种树都有高度 $H_i$,费用 $C_i$,数量 $P_i$,现要砍掉一些树,使得剩下的树中最高的树的数量超过一般,求最小的费用。($1 leq n leq 10^5, 1 leq H_i leq 10^9, 1 leq C_i leq 200, 1 leq P_i leq 10^9$)
分析
首先,容易想到我们应该枚举最高树的高度,将更高的全部砍掉,再从低的中选取k个费用最小的砍掉。
重点在于如何求出当前最小费用的k个。
注意到 $C_i$ 的范围非常小,所以我们可以统计费用为 $i$ 的树的个数,记为 $C[i]$(相当于建立200个桶)。
按高度从低到高排好序,遍历一遍,得到全局最小费用。复杂度为 $O(200n)$,如果二分查找就能做到 $O(log200cdot n)$.
#include<bits/stdc++.h> using namespace std; #define LL long long struct tree{ LL h,c,p; }a[100005]; bool cmp(tree a,tree b){ return a.h<b.h; } LL n; LL tmp=0,ans=0,tot=0; LL num[205]; int main(){ while(cin>>n){ memset(num,0,sizeof(num)); ans=tmp=tot=0; for(LL i=0;i<n;++i){ scanf("%lld%lld%lld",&a[i].h,&a[i].c,&a[i].p); tmp+=a[i].c*a[i].p; } ans=tmp; sort(a,a+n,cmp); for(LL i=0,j;i<n;i=j){ j=i;while(a[j].h==a[i].h&&j<n)++j; LL sum=0; LL cost=0; for(LL t=i;t<j;++t){ tmp-=a[t].c*a[t].p; tot+=a[t].p; sum+=a[t].p; } sum=tot-sum*2+1; for(LL w=1;sum>0;++w){ if(num[w]<=sum){ cost+=w*num[w]; sum-=num[w]; }else{ cost+=sum*w; break; } } ans=min(ans,cost+tmp); for(LL t=i;t<j;++t){ num[a[t].c]+=a[t].p; } } cout<<ans<<endl; } }
参考链接:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41065020