[蓝桥杯 2019 省 B] 后缀表达式

一.题目

题目描述

给定 N个加号、M 个减号以及 N+M+1个整数A1,A2,⋅⋅⋅,AN+M+1,小明想知道在所有由这 N个加号、M个减号以及 N+M+1个整数凑出的合法的后缀表达式中,结果最大的是哪一个?

请你输出这个最大的结果。

例如使用 1 2 3 + -,则 2 3 + 1 - 这个后缀表达式结果是 4,是最大的。

输入格式

第一行包含两个整数 NM

第二行包含 N+M+1个整数 A1,A2,⋅⋅⋅,AN+M+1

输出格式

输出一个整数,代表答案。

数据范围

0 ≤ N , M ≤ 105 ,
− 109 ≤ Ai ≤ 109

输入样例

1 1
1 2 3

输出样例

4

二.解释

看到题目如果有不知道后缀表达式是什么的人,可能会慌的一批,事实上这道题并不需要考虑后缀表达式的情况,只要考虑负负得正的问题。

我们来分类讨论一下:
第一种情况:全为加号,不论数据的运算顺序怎么变,结果都是一样的,所以只需要把所有的数加到一起即可;

第二种情况:此时必定有减号,以数据来分

1.所有数据都为非负数(>=0):
(1)偶数个减号,如5 + 4 + 3 - (1 - 2)= 5 + 4 + 3 + 2 - 1 = 13;
(2)奇数个减号,如5 + 4 - (1 - 2 - 3)= 5 + 4 + 3 + 2 - 1 = 13;
因此除最小的数,把剩下的数相加减去最小的数即可。
2.所有数据都为负数(< 0):
(1)偶数个减号,如 (-1) - (-2) - ((-3) + (-4) + (-5))  =  5 + 4 + 3 + 2 + (- 1) = 13;
(2)奇数个减号,如 (-1) - (-2) - (-3) - ((-4) + (-5))  =  5 + 4 + 3 + 2 + (- 1) = 13;
最后总会剩一个负数无法转化为正,所以每次都把最大的负数保留,剩下的全部取绝对值。
3.数据有正由负:
设有n个加号,m个减号
(1)当n = m = 2时,  (3 + 4 + 5) - (-4) - (-2)  =  5 + 4 + 3 + 2 + 1 = 15;
(2)当n = 3,m = 1时, 1 + 2 + 3 - ((-4) + (-5))  =  5 + 4 + 3 + 2 + 1 = 15;
(3)当n = 1,m = 3时, 5 - ((-4) + (-2) - 3 - 1)  =  5 + 4 + 3 + 2 + 1 = 15;
所有负数最后都会转化为正数,所以把所有数据的绝对值加起来即可。

三.代码

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cmath>
#include <string>
#include <vector>
#include <cstring>
#include <queue>
#include <unordered_map>

using namespace std;

typedef long long int64;

const int MaxN = 1e6 + 10;

int64 InN, InM, Res; 				//加号个数、减号个数、结果
int64 Ns[MaxN];						//保存序列的数组
unordered_map<int64, int64> Map;	//计算正负数个数

int main()
{
	cin >> InN >> InM;

	int64 Size = InN + InM + 1;
	for (int64 i = 1; i <= Size; i++)
	{
		scanf("%lld", Ns + i);
		if (Ns[i] < 0) { Map[-1]++; }
		else if (Ns[i] > 0) { Map[1]++; }
		else { Map[0]++; }
	}

	sort(Ns + 1, Ns + Size + 1);

	if (InM == 0)//没有减号的情况
	{
		for (int64 i = 1; i <= Size; i++) { Res += Ns[i]; }
	}
	else
	{
		if (Map[1] + Map[0] == Size)//没有负数的情况
		{
			for (int64 i = 2; i <= Size; i++) { Res += Ns[i]; }
			Res -= Ns[1];
		}
		else
		{
			if (Map[-1] == Size)//全为负数的情况
			{
				for (int64 i = 1; i < Size; i++) { Res += abs(Ns[i]); }
				Res += Ns[Size];
			}
			else//有正有负的情况
			{
				for (int64 i = 1; i <= Size; i++) { Res += abs(Ns[i]); }
			}
		}
	}

	cout << Res;

	return 0;
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值