一、题目描述
二、算法简析
显然,这道题要用贪心思想。想当然的,我们会先进行降序排序,将大的相加,在减去小的。然而,这种想法是错误的。因为这道题要求的是后缀表达式的最大值,为了便于理解,我们转换为中缀表达式的最大值,这里就有了一个隐含条件——中缀表达式可以加括号。
有了括号的加入,情况就变得复杂了。但并不总是如此。
- 1、当 \(M==0\) 时,即没有减号。
这时,无论我们怎样加括号,都是加法运算,也就是所有元素相加。 - 2、当 \(M > 0\) 时,即存在减号,至少有一个减号。
首先,我们知道数有 \(N + M + 1\) 个、符号有 \(N + M\) 个,所以两个数之间一定有一个符号。假设组合形式为符号
+数
,显然有 \(N+M\) 对,有一个数没有符号(相当于加号)。谁来当这个没有符号的数呢?从贪心的角度,应该选最大的数(毕竟相当于前面为加号),记为max
。
由于减号的存在,必然有一个数要被减去。我们当然希望这个数要小,所以选最小的数,记为min
。
我们将式子写成如下形式:max
_{} _{} ...-
(min
_{} _{} ...)
_
即符号,{}
为数。我们发现:对于一个数 \(a\),如果我们想加上它,可以与+
组合放在括号外,也可以与-
组合放在括号内(括号前为-
,负负得正);如果想减去它,可以与+
组合放在括号内,也可以与-
组合放在括号外。
这有什么用呢?先考虑符号无限多的情况,为了得到最大值,我们肯定加正数和减负数,相当于加一个数的绝对值。利用上面的发现,在+
和-
的数量有限时,无论一个数与哪个符号组合,只要调整这个组合的位置,就可以达到我们想要的加减状态——加上剩余数的绝对值。
注意,只要有一个减号,我们就能达到上述目的。
总结:
1、当 \(M==0\) 时,所有元素相加。
2、当 \(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 LOCAL
freopen("test.in", "r", stdin);
#endif
N = 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]);
}
else
for (int i = 0; i < A.size(); i++)
ans += A[i];
cout << ans << endl;
return 0;
}
完
标签:ch,符号,后缀,括号,int,减号,表达式 From: https://www.cnblogs.com/hoyd/p/18035735