一、题目描述
P8683 [蓝桥杯 2019 省 B] 后缀表达式
二、算法简析
显然,这道题要用贪心思想。想当然的,我们会先进行降序排序,将大的相加,在减去小的。然而,这种想法是错误的。因为这道题要求的是后缀表达式的最大值,为了便于理解,我们转换为中缀表达式的最大值,这里就有了一个隐含条件——中缀表达式可以加括号。
有了括号的加入,情况就变得复杂了。但并不总是如此。
- 1、当 M = = 0 M==0 M==0 时,即没有减号。
这时,无论我们怎样加括号,都是加法运算,也就是所有元素相加。 - 2、当 M > 0 M > 0 M>0 时,即存在减号,至少有一个减号。
首先,我们知道数有 N + M + 1 N + M + 1 N+M+1 个、符号有 N + M N + M N+M 个,所以两个数之间一定有一个符号。假设组合形式为符号
+数
,显然有 N + M N+M N+M 对,有一个数没有符号(相当于加号)。谁来当这个没有符号的数呢?从贪心的角度,应该选最大的数(毕竟相当于前面为加号),记为max
。
由于减号的存在,必然有一个数要被减去。我们当然希望这个数要小,所以选最小的数,记为min
。
我们将式子写成如下形式:max
_{} _{} …-
(min
_{} _{} …)
_
即符号,{}
为数。我们发现:对于一个数 a a a,如果我们想加上它,可以与+
组合放在括号外,也可以与-
组合放在括号内(括号前为-
,负负得正);如果想减去它,可以与+
组合放在括号内,也可以与-
组合放在括号外。
这有什么用呢?先考虑符号无限多的情况,为了得到最大值,我们肯定加正数和减负数,相当于加一个数的绝对值。利用上面的发现,在+
和-
的数量有限时,无论一个数与哪个符号组合,只要调整这个组合的位置,就可以达到我们想要的加减状态——加上剩余数的绝对值。
注意,只要有一个减号,我们就能达到上述目的。
总结:
1、当 M = = 0 M==0 M==0 时,所有元素相加。
2、当 M > 0 M > 0 M>0 时,加 max
,减 min
,再加上剩余数的绝对值。
三、本题代码
#include <bits/stdc++.h>using namespace std;typedef unsigned long long ull;int N, M;
vector<int> A;int quickin(void)
{int ret = 0;bool flag = false;char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') flag = true;ch = getchar();}while (ch >= '0' && ch <= '9' && ch != EOF){ret = ret * 10 + ch - '0';ch = getchar();}if (flag) ret = -ret;return ret;
}int main()
{#ifdef LOCALfreopen("test.in", "r", stdin);#endifN = quickin(), M = quickin();for (int i = 0; i < N + M + 1; i++){int a = quickin();A.push_back(a);}sort(A.begin(), A.end());ull ans = 0;if (M > 0){ans += A[A.size() - 1];ans -= A[0];for (int i = 1; i < A.size() - 1; i++)ans += abs(A[i]);}elsefor (int i = 0; i < A.size(); i++)ans += A[i];cout << ans << endl;return 0;
}
完