[堆]51 Nod 1461——穩定桌

題目描述

有一張桌子,有n個腿。第i根腿的長度是li。

現在要拿掉一些腿,使得桌子穩定,拿掉第i根腿需要di的能量。

穩定的條件是,假如拿掉若干條腿之後,桌子還有k個腿,那麼長度最長的腿的數目要超過一半。比如桌子有5根腿,那麼至少要有三根腿是最長的。另外,只有一根腿的桌子是穩定的,兩個腿的桌子想要穩定,必需長度是一樣的。

你的任務是拿掉若干腿,使得桌子穩定,並且所消耗的能量要最少。

解題思路

考慮枚舉長度,每個長度的個數我們可以知道。

那麼我們顯然要保留個數-1個小於該長度的能量最大的腿。

這個用兩個堆維護就可以了。

雖然保持堆中個數穩定是穩的,但是交換堆頂的複雜度不可估,但應該非常難卡。

#include<cstdio>
#include<queue>
#include<algorithm>
#define LL long long
using namespace std;
char nc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF;return *l++;
}
inline int _read(){
    int num=0;char ch=nc();
    while(ch<'0'||ch>'9') ch=nc();
    while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=nc();
    return  num;
}
const int maxn=100005;
struct jz{
    int x,w;
    bool operator<(const jz &b)const{return x<b.x;}
}a[maxn];
priority_queue<int> Q1;
priority_queue<int,vector<int>,greater<int> >Q2;
int n;
LL sum,ans,now;
int main(){
    freopen("exam.in","r",stdin);
    freopen("exam.out","w",stdout);
    n=_read();
    for (int i=1;i<=n;i++) a[i].x=_read();
    for (int i=1;i<=n;i++) a[i].w=_read(),sum+=a[i].w;
    sort(a+1,a+1+n);
    int i=1;
    while(i<=n){
        int j=i;LL tot=0;
        while(j<=n&&a[i].x==a[j].x) j++;
        while(Q2.size()<j-i-1&&!Q1.empty()) now+=Q1.top(),Q2.push(Q1.top()),Q1.pop();
        while(Q2.size()>j-i-1&&!Q2.empty()) now-=Q2.top(),Q1.push(Q2.top()),Q2.pop();
        while(!Q1.empty()&&!Q2.empty()&&Q2.top()<Q1.top()) now+=Q1.top()-Q2.top(),Q2.push(Q1.top()),Q1.pop(),Q1.push(Q2.top()),Q2.pop();
        while(i<j) tot+=a[i].w,Q1.push(a[i].w),i++;
        if (now+tot>ans) ans=now+tot;
    }
    printf("%lld\n",sum-ans);
    return 0;
}C++
發佈了157 篇原創文章 · 獲贊 61 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章