51nod 1053 最大M子段和 V2

来源:互联网 发布:同福3队吊打棒子知乎 编辑:程序博客网 时间:2024/05/16 12:09

N个整数组成的序列a[1],a[2],a[3],…,a[n],将这N个数划分为互不相交的M个子段,并且这M个子段的和是最大的。如果M >= N个数中正数的个数,那么输出所有正数的和。
例如:-2 11 -4 13 -5 6 -2,分为2段,11 -4 13一段,6一段,和为26。
(2 <= N , M <= 50000)

分析

需要猜一个结论:最大M子段和,必然由最大M+1子段和,通过删除一个子段,或将两个子段合成一个构造而成。

证明不会….

然后就可以用链表+堆做了。

但一个奇怪的发现是:这个算法的后半部分等价于将所有正数取负,把相邻的负数缩成一个,然后在序列中选取m个不相邻元素的最大值…这两个问题莫不是什么对偶之类的…

代码

#include <bits/stdc++.h>#define mp std::make_pair#define f first#define s second#define pair std::pairtypedef long long ll;const int N = 50010;int read(){    int x = 0, f = 1;    char ch = getchar();    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}    return x * f;}int n,m,now;int l[N * 4],r[N * 4];ll sum[N];int a[N];ll tab[N * 4];int top;int use[N * 4];std::priority_queue<pair<ll, int> > Q;int main(){    n = read(), m = read();    for (int i = 1; i <= n; i++)        a[i] = read(), sum[i] = a[i] + sum[i - 1];    int last = 0, cnt = 0;    ll ans = 0;    for (int i = 1; i <= n; i++)    {        if (a[i] >= 0)        {            cnt++;            if (last != 0)                tab[++top] = sum[i - 1] - sum[last];            ans += a[i];            tab[++top] = -a[i];            last = i;        }    }    if (cnt <= m)    {        printf("%lld\n",ans);        return 0;    }    for (int i = 1; i <= top; i++)        l[i] = i - 1, r[i] = i + 1;    r[top] = 0;    for (int i = 1; i <= top; i++)        Q.push(mp(tab[i], i));    for (int i = cnt; i > m; i--)    {        while (use[Q.top().s])            Q.pop();        pair<ll, int> p = Q.top();        Q.pop();        ans += p.f;        int id = p.s;        use[id] = 1;        if (!l[id] || !r[id])        {            if (!l[id])                use[r[id]] = 1, l[r[r[id]]] = 0;            else use[l[id]] = 1, r[l[l[id]]] = 0;        }        else        {            int L = l[id], R = r[id];            tab[++top] = tab[L] + tab[R] - tab[id];            use[L] = use[R] = 1;            r[l[L]] = l[r[R]] = top;            l[top] = l[L], r[top] = r[R];            Q.push(mp(tab[top], top));        }    }    printf("%lld\n",ans);}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 养了个白眼狼怎么办 孩子学东西很慢怎么办 手不小心碰肿了怎么办 腿中间摩擦的疼怎么办 晚上睡觉时双腿酸胀怎么办 腿擦破皮了怎么办 快速好 宝宝腿擦破皮了怎么办 新生儿睡觉腿喜欢弯曲怎么办 孩子八个月交叉走路怎么办 胫椎引起双腿发热怎么办 婴儿头型睡扁了怎么办 膝盖抻筋了疼怎么办 小腿肚子抻筋了怎么办 后背抻筋了 很疼怎么办 运动膝盖抻着了怎么办 大腿内侧抻着了怎么办 大腿抻筋了 很疼怎么办 小腿肚子聚筋了怎么办 6个月婴儿腿弯怎么办 胳膊抻筋拉伤了怎么办 宝宝抻着了怎么办妙招 拎东西胳膊抻了怎么办 小臂一用力筋疼怎么办 摔破胳膊很痛怎么办 胳膊的筋扭伤了怎么办 小孩胳膊抻筋了怎么办 肩膀抻着了怎么办妙招 右边肩膀抻着了怎么办 胳膊因劳累很痛怎么办 宝宝胳膊摔了疼怎么办 宝宝胳膊抻筋了怎么办 孕妇胳膊筋伤了怎么办 刚进公司就怀孕怎么办 撞到胳膊麻筋了怎么办 腰抻了怎么办多久能好 腰突然抻了一下怎么办 干活抻筋了 很疼怎么办 胳膊抻筋一动就疼怎么办 肩膀受风了很疼怎么办 开空调受风了怎么办 胳膊受风了疼怎么办