• 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
  • 相关阅读:
    【资源分享】一个匿名文件分享网站
    【C语言】指针到底有什么用
    【C语言】一招搞定C语言各种复杂指针
    【资源分享】Visual Studio全版本在线安装包(5MB)
    【资源分享】C语言也能干大事(第二版)
    【资源分享】迅雷
    Nuxt spa deploy
    nginx ssl docker
    Linux查看环境变量
    Nginx 配置
  • 原文地址:https://www.cnblogs.com/galaxies/p/hdu1024-another.html
Copyright © 2020-2023  润新知