题目描述
给定 N 个加号、M 个减号以及 N + M + 1个整数 A1,A2,···,AN+M+1,小明想知道在所有由这 N 个加号、M 个减号以及 N + M +1个整数凑出的合法的后缀表达式中,结果最大的是哪一个?
请你输出这个最大的结果。
例如使用 1 2 3 + -,则 “2 3 + 1 -” 这个后缀表达式结果是 4,是最大的。
输入描述
第一行包含两个整数 N , M。
第二行包含 N + M + 1个整数 A1,A2,··· ,AN+M+1。
其中,0≤N,M≤105 ,−109≤Ai≤109。
输出描述
输出一个整,代表答案。
输入输出样例
示例
输入 |
---|
1 1 1 2 3 |
输出 |
---|
4 |
运行限制
最大运行时间:1s
最大运行内存: 256M
代码
#include <iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
vector<long long>ve;
int main()
{
long long sum=0;
int n, m,x;
cin >> n >> m;
x = 0;
long long a;
for (int i = 0; i < n + m + 1; i++)
{
cin >> a;
sum += a;
ve.push_back(a);
if (a < 0)x++;
}
if (m == 0)cout << sum << endl;//没有减号的话直接输出
else
{
sort(ve.begin(), ve.end());//由小到大排序
if (x)
{
if (x != n + m + 1) {//如果不全是负数
for (int i = 0; i < x; i++)
{
sum -= 2 * ve[i];//将负数变为正数
}
}
else
{//全是负数,将除了最后一项其余都变为正数
for (int i = 0; i < x-1; i++)
{
sum -= 2 * ve[i];
}
}
}
else
{//如果不存在负数且有减号,则减去最小的正数
sum -= 2 * ve[0];
}
cout << sum << endl;
}
return 0;
}
思路
对于题目中的后缀表达式的理解很关键,在这里表达式中可以通过添加括号的方式来调整结果大小。
例如:
1 1
-2 -5 3
则结果最大的情况为3-((-2)+(-5))=10,而不是单纯的排序后将大的数字相加减去小的数字。
所以最先分出来的情况是有没有负号,可以知道只要有负号就可以通过添加括号的方式来将负数变为正数。没有负号的时候只需要相加即可,有了负号还需要考虑别的情况。就是有没有负数的情况,第一种情况,没有负数,这时候无论有多少个负号,都可以变换为其余的数字减去最小的正数的式子。例如:
3 2
1 2 3 4 5 6
则可以变为6+5+4-(1-(3+2))=19
所以没有负数但是有减号的情况只需要减去最小的正数就可以得到最大的结果。
如果既有负数又有减号则需要分两种情况,一种是不全是负数,一种是全是负数。不全是负数的话总能将负数全部通过加括号的形式变为正数,例如:
1 2
2 -3 -4 -5
则可以变为2-((-4)+(-5))-(-3)=14。
第二种情况,全部为负数而且有负号,除了一个负数无法变为正数其余均可变为正数,所以将最大的负数保留,其余全部变为正数,例如:
1 2
-1 -2 -3 -4
则变为-1-((-3)+(-4))-(-2)=8。
以上是对题目中所有情况的分析,对应代码中的不同情况。