您的位置:首页 > 其它

[堆]51 Nod 1461——稳定桌

2017-10-25 18:02 197 查看

题目描述

有一张桌子,有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++
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: