1247-后缀表达式
题目描述
关系
内容
给定
请你输出这个最大的结果。
例如使用
输入格式
第一行包含两个整数
第二行包含
输出格式
输出一个整数,代表答案。
数据范围
输入样例:
1 1
1 2 3
输出样例:
4
问题分析
最初思路
主要矛盾显然是负数,我们希望,负数尽可能作为被减数。
思路分析
这道题的题眼就是我们可以任意设置括号的位置,来改变运算意义上加号和减号的数量。什么是运算意义上的减号?就是去掉所有括号后,算术表达式实际的加号减号的数量。
而减号是主要矛盾,因为减号决定原数是否进行变号。
直接上结论:
- 如果减号数量为 0(
),那么结果就为所有数加起来。 - 如果减号数量
, 那么我就可以凑出 个运算意义上的减号;
所以,如果出现了负数,那么就用负号与之配对。将负数变为正数,如果出现正数,就用加号与之配对。如果给出的数没有正数,那么就把最小的负数与加号配对。
为什么呢?因为这是后缀表达式,所以,我们可以任意的加括号。即,有如下的形式:
可以发现,当减号数量为 1 的时候,我们可以通过把加号放到括号,来让其变为运算意义上的减号。
当减号数量
同理,当我们希望减号为加号的时候,就将其放入括号内,当我们希望减号时,就拿出括号。例如,如何凑出
上述式子的运算意义上的减号数量为
执行流程设计
- 如果
。那么就直接输出累加和; - 如果
,假设负数有 k 个: (全部为负数),那么我们就凑出 个负号(将剩余的 个负数转化为正数),再将最大的负数保留符号; (存在正数),那么我们就凑出 k 个减号与其配对; ,只凑出一个减号,即将最小的正数转化为负数;
可以发现,最终的结果可以统一表示为我们先挑选出最大值和最小值,先把最小值反转一个符号,最大值不变号。
总结
代码实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m;
int a[N * 2];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n + m + 1; i++) scanf("%d", &a[i]);
ll res = 0;
if (m == 0) {
for (int i = 0; i < n + m + 1; i++) res += a[i];
} else {
sort(a, a + n + m + 1);
res = a[n + m] - a[0];
for (int i = 1; i < n + m; i++) res += abs(a[i]);
}
printf("%lld\n", res);
return 0;
}