51nod 1461

原题链接

将桌腿按长度排序,枚举终态的最长桌腿长度L,假设该长度的桌腿有M条,显然长度大于L的桌腿必须去掉,剩下长度小于L的保留花费最大的M-1条即可。

用大根堆保存长度小于L的桌腿。

#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<fstream>
#include <iostream>
#include<algorithm>
#define debug puts("ssssssssssss")
#define ll long long
#define MP make_pair
#define mm(a,b) memset(a,b,sizeof(a))
#define rep(a,b) for(int a=1;a<=b;a++)
#define e 2.7182818284590452354
using namespace std;
const int MOD=100000007;
const int maxb=500+10;
const int MAXN=100005;
const int maxn=1005;
const double eps=1e-10;
int n, k;
struct node{
    int li, di;
    bool operator <(const node &a)const{
        return li<a.li;
    }
};
node dk[MAXN];
int li[MAXN];
ll sum[MAXN];
priority_queue<int,vector<int>,greater<int> > Q1, Q2;
int main(){
//    ifstream fin("in.txt");
//    ofstream fout("out.txt");
    int n;

    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&dk[i].li);
    for(int i=1;i<=n;i++) scanf("%d",&dk[i].di);
    sort(dk+1,dk+1+n);
    dk[0].li=-1;
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+dk[i].di;
    }
    ll ans=sum[n], sum1=0;
    for(int l=1;l<=n;l++){
        if(dk[l].li!=dk[l-1].li){
            int r=l;
            while(r+1<=n&&dk[r+1].li==dk[l].li) r++;
            ll temp=sum[n]-sum[r];
            int len=r-l+1;
            if(len>=2){
                int lim=min(l-1,len-1);
                while(!Q1.empty()&&!Q2.empty()&&Q1.top()<-Q2.top()){
                    int reg=Q1.top();
                    sum1-=Q1.top();
                    Q1.pop();
                    Q1.push(-Q2.top());
                    sum1-=Q2.top();
                    Q2.pop();
                    Q2.push(-reg);
                }
                while(Q1.size()<lim&&!Q2.empty()){
                    sum1-=Q2.top();
                    Q1.push(-Q2.top());
                    Q2.pop();
                }
                while(Q1.size()>lim){
                    sum1-=Q1.top();
                    Q2.push(-Q1.top());
                    Q1.pop();
                }
                temp+=sum[l-1]-sum1;
            }else{
                temp+=sum[l-1];
            }
/*            if(ans>temp){
                printf("l=%d r=%d\n",l, r);
                printf("sum1=%lld\n",sum1);
            }*/
            ans=min(ans,temp);
        }
        Q1.push(dk[l].di);
        sum1+=dk[l].di;
    }
    printf("%lld\n",ans);

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值