9.8 杰瑞

题意

给定一个算式,这个算式有\(n\)个正整数,并有\(n-1\)个运算符符将其连接,且只有可能是\(+\)\(-\)

请给这个算式添加若干个合法的(这里的合法指的是数学中的合法)括号,使得这个算式的运算结果最大

解法

很有意思的一道题

然而我并没有想出来

首先把连续的用\(+\)号连接的正数合到一起,可以很方便的证明这样做对答案没有影响

处理后的数组有如下的性质

  • 每个\(+\)号前后一定是\(-\)
  • 若有两个连续的\(-\)号,如果在第一个\(-\)号后添上括号,之后的所有数字都可以取到正值(具体来说,首先我们会损失第一个数字,但我们可以用括号将所有\(+\)号连接的两个数括起来,这样第一个数字后的所有数字都可以为正)

以上运用了一点贪心的思想

接下来我们从后往前进行\(DP\)

  • \(a[i]>0\)

    • 加不加括号都没关系

      \(f[i]=a[i]+f[i+1]\)

  • \(a[i]<0\)

    • 不加括号

      \(f[i]=a[i]+f[i+1]\)

    • 加一个括号

      • \(a[i+1]<0\)

        根据之前提到的性质

        \(f[i]=max(f[i], a[i]+sum[i+1])\)

      • \(a[i+1]>0\)

        这样我们不得不损失前两个数,但是这个正数后一定是一个负数(之前的性质)

        \(f[i]=max(f[i], a[i]-a[i+1]+sum[i+2])\)

这里的\(sum[i]\)指的是后缀绝对值和

这样\(DP\)后输出\(f[1]\)即可

代码

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 1e6 + 10;

int n, cnt, T;
long long a[N], b[N], f[N], sum[N];

long long abS(long long x) {
    return x < 0 ? -x : x;  
}

int main() {
    
//  freopen("jerry.in", "r", stdin);
    
    scanf("%d", &T);    
    
    while (T--) {
        
        scanf("%d", &n);
        
        for (int i = 1; i <= n; ++i) {
            int ch = getchar(), f = 1;
            a[i] = 0;
            while (!isdigit(ch))    
                ch == '-' ? f = -1, ch = getchar() : ch = getchar();
            while (isdigit(ch))     
                a[i] = a[i] * 10 + ch - 48, ch = getchar();
            a[i] *= f;
        }
        
        cnt = 0;
        for (int i = 1; i <= n; ++i) {
            b[++cnt] = a[i];
            while (b[cnt] > 0 && a[i + 1] > 0 && i < n) b[cnt] += a[++i];
        }
        
        n = cnt;
        
        sum[n + 1] = 0;
        for (int i = n; i >= 1; --i)
            sum[i] = sum[i + 1] + abS(b[i]);
        
        f[n] = b[n];
        for (int i = n - 1; i >= 1; --i) {
            if (b[i] >= 0)
                f[i] = b[i] + f[i + 1];
            else {
                if (b[i + 1] < 0)
                    f[i] = b[i] + sum[i + 1];
                else
                    f[i] = b[i] - b[i + 1] + sum[i + 2];
                f[i] = max(f[i], b[i] + f[i + 1]);
            }
        }
        
        printf("%lld\n", f[1]);
    }
    
    
    return 0;
}

/*
1
3
5 - 1 - 3
*/

转载于:https://www.cnblogs.com/VeniVidiVici/p/11508545.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值