hdu1024 Max Sum Plus Plus的另一种解法

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1024

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1053

【题解】

原来的解法:http://www.cnblogs.com/galaxies/p/hdu1024.html

原来的解法思路是正着,我们加数,现在考虑删数

我们先特判几种情况(可以全选正,全选正还不够)

现在只剩下一种情况,段数<正数段数

我们可以把数字合并变成+/-/+/-...这个情况

那我们考虑的是合并。

每次我们选出+的段,意为舍弃这一段

选出-的段,意为把这一段和旁边两个正段合并

所以选出代表要把这段绝对值从答案里减去,我们希望越小越好,所以维护一个小根堆(或set)

那么合并的时候把选出的段和旁边两段直接相加即可,由于这个绝对值是最小的,所以加起来还是旁边两段的符号。

特别注意如果在边界上出现了负数那么这个负数是没有任何用的,因为我们选他不能合并来使段数减小,所以直接删掉即可。

进队列的时候如果边界上出现了0,那么一样把它删掉,因为选0一定是出现这种情况

10000 -10000 -10000 ....

然后你选了第一个,变成了0 -10000 ...

很明显我们第一次选了10000,意为舍弃它,并合并,所以和周围合并变成了0,再选0,没有任何意义,不能使段数减小,反而增加。

至于为什么不能在取top的时候判,因为会有这种情况

m=1,n=4,a[]={0,-1,-1,0}

原本是0,就已经合法,是有实际意义的,所以不能判掉。

然后就过了

# include <set>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 1e6 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

ll a[M], ans = 0;
int m, n;
int p[M], pn;
int tot1, tot2;
set< pair<ll, int> > s;

inline int sgn(int x) {return x<0?1:0;}
inline ll myabs(ll x) {return x>0?x:-x;}

inline void transform() {
    n = 0;
    ll t = p[1]; int s = sgn(t);
    for (int i=2; i<=pn; ++i) {
        if(sgn(p[i]) == s)
            t += p[i];
        else {
            a[++n] = t;
            t = p[i];
            s = sgn(t);
        }
    }
    a[++n] = t;
//    for (int i=1; i<=n; ++i) printf("%d ", a[i]);
}

int Minus[M];
inline void solve_minus() {
    int tn = 0, tem = m-tot1;
    for (int i=1; i<=pn; ++i) if(p[i] < 0) Minus[++tn] = p[i];
    sort(Minus+1, Minus+tn+1);
    while(tem--) ans += Minus[tn--];
}

int L[M], R[M];

inline void del(int x) {
    L[R[x]] = L[x];
    R[L[x]] = R[x];
}

inline void solve() {
    s.clear();
    int T = tot2 - m;
    for (int i=0; i<=n+1; ++i) L[i] = R[i] = 0;
    for (int i=1; i<n; ++i) L[i] = i-1, R[i] = i+1;
    L[n] = n-1;
    for (int i=1; i<=n; ++i) s.insert(make_pair(myabs(a[i]), i));
//    cout << T << endl;
    while(T--) {
        pair<ll, int> top = *s.begin(); 
        s.erase(top);
        int x = top.second, y;
        if(a[x] < 0 && (!L[x] || !R[x])) {
            del(x);
            ++T;
            continue;
        }
        ll sum = a[x];
        ans -= myabs(sum);
        if(L[x]) {
            y = L[x];
            sum += a[y];            
            s.erase(make_pair(myabs(a[y]), y));
            del(L[x]);
        }
        if(R[x]) {
            y = R[x];
            sum += a[y];
            s.erase(make_pair(myabs(a[y]), y));
            del(R[x]);
        }
        a[x] = sum;
        if(sum == 0) del(x);
        else s.insert(make_pair(myabs(a[x]), x));
    }
}

int main() {
    while(cin >> m >> pn) {
        tot1 = tot2 = 0;
        for (int i=1; i<=pn; ++i) scanf("%d", p+i);
        transform();
        for (int i=1; i<=pn; ++i) tot1 += (p[i] >= 0);
        for (int i=1; i<=n; ++i) tot2 += (a[i] >= 0);
        ans = 0;
        for (int i=1; i<=n; ++i) 
            if(a[i] >= 0) ans += a[i];
//        for (int i=1; i<=n; ++i) cout << a[i] << ' ';
//        cout << endl;
//        cout << "ans = " << ans << endl;
        if(tot2 <= m && m <= tot1) cout << ans << endl;
        else if(m > tot1) {
            solve_minus();
            cout << ans << endl;
        } else {
            solve();
            cout << ans << endl;
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/galaxies/p/hdu1024-another.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值