题意:
给出一个桌子,有n个腿,每个腿的长度是l,拆掉这条腿的花费是d,当最长的腿占腿总数大于其他腿的总数,那么合法,问到达合法情况的最小代价。
解题思路:
首先根据长度排个序,然后枚举每种长度作为最长长度。枚举到当前长度时,相同长度不砍,把比当前长度大的全砍掉(这个比较容易维护),然后再看现在是否已经满足条件,,不满足则从前面费用小的开始砍,直到满足为止。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <queue>
#define LL long long
#define fir first
#define sec second
using namespace std;
int n;
LL num[233333],s[233333],maxl,cost,ans,sl[233333];
pair<LL,LL>leg[233333];
multiset<LL>q;
//priority_queue<LL,vector<LL>,greater<LL> >q;
LL gao[233333];
int main(){
ans=(LL)2333333333333333;
scanf("%d",&n);
memset(sl,0,sizeof(sl));maxl=0;memset(num,0,sizeof(num));
for(int i=1;i<=n;i++){scanf("%I64d",&leg[i].fir);maxl=max(maxl,leg[i].fir);}
for(int i=1;i<=n;i++)scanf("%I64d",&leg[i].sec);
sort(leg+1,leg+1+n);
for(int i=1;i<=n;i++){num[leg[i].fir]++;sl[leg[i].fir]+=leg[i].sec;}
for(int i=1;i<=maxl;i++)s[i]=s[i-1]+sl[i];
int j=1;
for(int i=1;i<=maxl;i++){
if(s[i]==s[i-1])continue;
cost=0;
while(leg[j].fir<i)j++;
set<LL>::iterator it=q.end();
if(!q.empty())it--;
for(int k=1;k<=num[i]-1;k++){
if(q.empty())break;
cost+=*it;
if(it==q.begin())break;
it--;
}
cost=s[i-1]-cost;
cost+=s[maxl]-s[i];
ans=min(ans,cost);
while(leg[j].fir==i){
q.insert(leg[j].sec);
if(j==n)break;
j++;
}
}
printf("%I64d\n",ans);
return 0;
}