后缀&前缀&中缀表达式
1.算法分析
对于任意一个前缀、中缀、后缀表达式,都可以对应到一颗树,该树的叶子节点为数字,根节点为符号。如下图所示:
而前缀、中缀、后缀表达式分别是对该树进行前序、中序、后序遍历得到的表达式。
该树前缀表达式、中缀表达式、后缀表达式的答案一样,因此,如果希望得到前缀和后缀表达式的值,直接转化为求中缀表达式的值,等于树的: val(左子树) op val(右子树), 其中的op表示运算符号。
定义整棵树的权值为该树对应的中缀表达式的值。而由于不同根节点允许赋的符号不同,得到的整棵树的权值也不同,这就有了求最值的问题。
设加号有n个,减号有m个,那么一旦m>0,便可以构造出减号1 ~ n+m,加号1 ~ n+m,即最少构造出一个加号、一个减号,其余n+m-2个符号任意。如下图所示:
2.典型例题
第十届蓝桥杯 c/c++ 省赛b组 I: 后缀表达式
题意: 给定 N 个加号、M 个减号以及 N + M + 1 个整数 A1, A2, · · · , AN+M+1,小 明想知道在所有由这 N 个加号、M 个减号以及 N + M + 1 个整数凑出的合法的 后缀表达式中,结果最大的是哪一个? 请你输出这个最大的结果。例如使用1 2 3 + -,则 “2 3 + 1 -” 这个后缀表达式结果是 4,是最大的。 0 ≤ N , M ≤ 100000 , − 1 0 9 ≤ A i ≤ 1 0 9 0 ≤ N, M ≤ 100000,−10^9 ≤ Ai ≤ 10^9 0≤N,M≤100000,−109≤Ai≤109
题解: 对于任意一个后缀表达式都可以对应到一颗树,该树的叶子节点是所有的数字,根节点是符号。对于这样一棵树只要存在“-”号节点,那么就能够构造出负数1 ~ n+m个,正数1 ~ n+m个,即最少一个正数、一个负数,其他数字的符号任意。因此只需要将原数列排序,最大的取正好,最小的取符号,中间的都取绝对值即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 2e5 + 10;
typedef long long LL;
int n, T, m, a[N];
int main() {
cin >> n >> m;
int k = n + m + 1;
for (int i = 1; i <= k; ++i) scanf("%d", a + i);
LL res= 0;
if (!m) {
for (int i = 1; i <= k; ++i)
res += a[i];
}
else {
sort(a + 1, a+ k + 1);
res = a[n+1+m]-a[1];
for (int i = 2; i <= n + m; ++i) res += abs(a[i]);
}
cout << res << endl;
return 0;
}