【BZOJ】2288: 【POJ Challenge】生日礼物-贪心+链表+堆

传送门:bzoj2288


题解

将正负相同的连续区间缩成一块,数列就转成了正负相间的了。
设为正的有 n n n段且和为 s u m sum sum
n ≤ m n\leq m nm答案就是 s u m sum sum
否则每次取出绝对值最小的一块 a i a_i ai(除两端的负块)将其与旁边的块合并,使得:
n − 1 , s u m − ∣ a i ∣ n-1,sum-|a_i| n1,sumai
(抛掉正块/选择负块)


代码

#include<bits/stdc++.h>
#define pii pair<int,int> 
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=100005;
int n,m,cnt,ans,l[N],r[N],a[N];
bool mark[N];
priority_queue<pii,vector<pii>,greater<pii> >q;

void del(int x)
{
    mark[x]=1;
    l[r[x]]=l[x],r[l[x]]=r[x];
}

int main(){
    n=getint(),m=getint();
    int x,tmp=0;
    for(int i=1;i<=n;i++)
    {
        x=getint();if(!x)continue;
        if(1ll*a[tmp]*x>0)a[tmp]+=x;
        else a[++tmp]=x;
    }n=tmp;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>0)cnt++,ans+=a[i];
        l[i]=i-1,r[i]=i+1;
        q.push(make_pair(abs(a[i]),i));
    }
    while(cnt>m)
    {
        while(mark[q.top().second])q.pop();
        int x=q.top().second;q.pop();
        if((l[x]&&r[x]!=n+1)||(a[x]>0))
        {
            --cnt,ans-=abs(a[x]);
            a[x]+=a[l[x]]+a[r[x]];
            q.push(make_pair(abs(a[x]),x));
            del(l[x]),del(r[x]);
        }
        else del(x);
    }
    printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值