第十届 蓝桥杯软件类 C或C++程序设计 本科B组 省赛 第9题 后缀表达式

蓝桥杯 历届真题 题解目录

试题 I: 后缀表达式

时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分
 
【问题描述】
  给定 N 个加号、M 个减号以及 N + M + 1 个整数 A1,A2,··· , A N + M + 1 A_{N+M+1} AN+M+1,小明想知道在所有由这 N 个加号、M 个减号以及 N + M +1 个整数凑出的合法的 后缀表达式中,结果最大的是哪一个?
  请你输出这个最大的结果。
  例如使用1 2 3 + -,则 “2 3 + 1 -” 这个后缀表达式结果是 4,是最大的。
 
【输入格式】
  第一行包含两个整数 N 和 M。 第二行包含 N + M + 1 个整数 A1,A2,··· , A N + M + 1 A_{N+M+1} AN+M+1
 
【输出格式】
  输出一个整数,代表答案。
 
【样例输入】
  1 1
  1 2 3
 
【样例输出】
  4
 
【评测用例规模与约定】
  对于所有评测用例, 0 ≤ N , M ≤ 100000 , − 1 0 9 ≤ A i ≤ 1 0 9 0≤ N,M ≤100000,-10^9 ≤ Ai ≤10^9 0N,M100000109Ai109

分析:
  本来我一看这题下意识以为是动态规划的,就像蓝桥杯题库的那道最大的算式一样。
  但是吧,最大的算式中要求N个数的相对位置不能改变,就没法贪心了。而这个题就不同了,他说只要是合法的后缀表达式就行。况且最大的算式N最大才15,这道题n+m+1可是200001!dp[200001][200001]的数组全局变量都放不下。。。
  言归正传。很多人都认为,后缀表达式是没有括号的,所以不用考虑a-(b+c)的情况出现,但是却不然。
   a b c + − a b c + - abc+这个后缀表达式是怎么算的?就是a-(b+c)。所以后缀表达式是要考虑括号的。
  首先,如果有括号,会造成什么效果?当然就是传说中的负负得正了~
  比如:1-((-2) + (-3) + (-4)) - (-5) - (-6) + 7 + 8 + 9 + 10 = 55;大家发现了什么?显然结果就是序列绝对值的和。
  但我们要考虑几种特别情况:第一,如果我没有减号,只有加号,显然括号不会对其运算结果有任何影响,直接相加即可。
  第二,如果我们有减号,却没有负数,总有一项没法负负得正,就只好牺牲最小的正数了。例如:
  1 3
  1 2 3 4 5
  就只好5 + 4 - (1 - 2 - 3) = 5 + 4 + 3 + 2 - 1 = 14了。
  同样,如果没有正数,那么表达式中的第一个数无论怎样都无法负负得正的,这时就要牺牲最大的负数,即绝对值最小的负数。例如:
  0 2
  -1 -2 -3
  就只好-1 - (-2) - (-3)= 3 + 2 - 1 = 5了。
  否则,但凡有一个减号,有负数也能变成绝对值相加。


2020-3-31更新:
  最开始我没有考虑数据范围,这道题结果的最大值是200001*1e9,是超过int范围的,但并不超过long long,所以获取结果的变量ans应该定义成long long。这里感谢博友的提醒φ(* ̄0 ̄),如果还有什么问题,也希望大家一起讨论,谢谢啦§( ̄▽ ̄


2020-9-18更新:
  初值不记得当初为什么设的1和-1了,这里主要是判断是否有负数或者是否有正数用的,谢谢博友提醒,现在改过来了,变为下面的整形极限值。
  这1和-1连我自己的样例都跑不过,我也是醉了,什么时候变成1和-1的……[・_・?]

/* int MIN = 1, MAX = -1; */
int MIN = INT_MAX, MAX = INT_MIN;

代码如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

int n, m, len;
int *a;
long long ans = 0;
int MIN = INT_MAX, MAX = INT_MIN;

int main()
{
	freopen("text.ini", "r", stdin);

	cin >> n >> m;		//n个+,m个-
	len = n + m + 1;

	a = new int[len];
	for (int i = 0; i < len; i++)
	{
		cin >> a[i];
		MIN = min(MIN, a[i]);
		MAX = max(MAX, a[i]);
	}

	if (!m)
	{	//如果没有减号
		for (int i = 0; i < len; i++)
			ans += a[i];
	}
	else
	{	//如果有减号
		for (int i = 0; i < len; i++)
			ans += abs(a[i]);
		//如果没有负数,结果应减去最小值。
		if (MIN > 0) ans -= MIN * 2;
		//如果没有正数,结果应加上最大值
		if (MAX < 0) ans += MAX * 2;
	}
	
	cout << ans << endl;

	cout << "over" << endl;
	while (1);
	return 0;
}

附带个人写的几个样例:
样例输入1:
 1 1
 2 -1 -1
样例输出1:
 4
样例1解释:
 2 - ((-1) + (-1)) = 4
 
样例输入2:
 1 1
 1 2 3
样例输出2:
 4
样例2解释:
 3 + 2 - 1 = 4
 
样例输入3:
 2 2
 1 -2 3 -4 5
样例输出3:
 15
样例3解释:
 5 + 3 + 1 - (-2) - (-4) = 15
 
样例输入4:
 5 5
 1 -2 -3 -4 5 -6 -7 -8 -9 -10 -11
样例输出4:
 66
样例4解释:
 1 + 5 - ((-2) + (-3) + (-4) + (-6) + (-7)) - (-8) - (-9) - (-10) - (-11) = 66

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值