蓝桥杯 2019省赛 后缀表达式
思路
完全错误的思路
用贪心的想法,加大的,减小的。然后发现WA了
正确思路
后缀表达式加括号
关于后缀表达式其实有个点是容易被忽略的(也是为什么上面暴力贪心忽略的一个要点):其实后缀表达式也是可以加括号的(为什么可以加括号?因为那道后缀表达式加括号进行计算的模拟题我没过)
换句话说,中缀表达式中括号加上减号的一些骚操作是可以在后缀表达式中实现的。
括号与减号
加法其实比较普通(毕竟加再多括号还是求个和),但是减法就有点特殊的性质了。
- 如果将加法式子括起来,前面放个减号,那么里面的加号全变成减号了。
- 如果括起来的是减号(或者负数),那么就变成加绝对值了。
基于这个性质,(其实还是贪心),就可以通过贪心将负数和减号尽量减到最少。
因此,如果没有减号的话,输出所有数字的和即可。
如果可以存在减号的话,那么就可以任意对数字进行加或者减。
- 如果存在负数的话,那么要尽量让负数转为正数,也就是把所有负数加个括号扩上即可。
- 如果没有负数的话,根据之前的想法,多个负号其实可以削减为一个,也就是说多个负号可以减到1个。那么,按照贪心的思想,直接最大值减去最小值即可。
综合上面存在减号的情况,一开始让最大值减去最小值就行了。如果存在负数,那么负数也会被转为正数。如果没有存在负数,那么减去一个最小的正数也符合贪心思想。剩下的直接加上绝对值即可。
代码(C++)
一种可行的c++代码实现。
#include <bits/stdc++.h>
typedef long long ll;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<ll>v(n + m + 1);
for (int i = 0; i < v.size(); ++ i)
std::cin >> v[i];
std::sort(v.begin(), v.end());
ll ans = 0;
if (m == 0) {
for (int i = 0; i < v.size(); ++ i) {
ans += v[i];
}
} else {
ans = v.back() - v.front();
for (int i = 1; i < v.size() - 1; ++ i) {
ans += std::abs(v[i]);
}
}
std::cout << ans << '\n';
return 0;
}