2019牛客多校C Governing sand

题意

有 $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(log200\cdot 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

猜你喜欢

转载自www.cnblogs.com/lfri/p/11324224.html