[蓝桥杯] 后缀表达式 | 贪心

1247后缀表达式

后缀表达式

题目:

给定 N 个加号、M 个减号以及 N+M+1 个整数 A1,A2,···,AN+M+1,小明想知道在所有由这 N 个加号、M 个减号以及 N+M+1 个整数凑出的合法的后缀表达式中,结果最大的是哪一个?

例如使用 123+,则 23+1 这个后缀表达式结果是 4,是最大的。


题目大意:n+1个+ m个-加入到表达式中使得整个序列最大

分析:
这个题目贪心的关键是考虑到负号的数目不是m个,而是1到m+n个
考虑系列如下:
\(\text{target}:\max(a_1+a_2+...+a_{i-1})-\min(b_i-b_{i+1}-...-b_n)\)
其中\(\min()\)中可以有负号和正号,展开式子之后得到的是其取反,因此考虑极端的状态如果所有的\(n-1\)个+放在\(\min\)中,\(m-1\)个-放在\(\max\)中,那么总共就有\(n+m\)个负数。同理的,可以在确定了两个数分别作为\(a_1\)\(b_{i+1}\)之后,就只需在两个数列中继续加入数字即可。

即把一个负号提出来剩余负号都在b中那么就只有一个负号
如果把一个负号提出来m-2个负号在b中那么就有2个负号
...
以此类推从总共可以有m+n到1个负号
至少有一个加号,至少有一个负号

那么因此序列如下:
\(\text{target}:\max(a_1(-/+)a_2(-/+)...(-/+)a_n)-\min(b_i(-/+)b_{i+1}(-/+)...(-/+)b_n)\)

贪心策略:为了使得\(\text{target}\)最大,我们尽量把所有的负数加到右边,把正数加到左边。那么相当于取到其他的数的绝对值。
因此总的答案应该是 \(a\) 排序后,\(\sum_{i=2}^{n-1}\text{abs}(a[i])-a[1]+a[n]\)

//#define judge
// Author: oceanlvr
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn];
string s;
int n, m;
ll res;
int main() {
#ifndef judge
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  cin >> n >> m;
  for (int i = 1; i <= n + m + 1; i++) cin >> a[i];
  if (m == 0) {
    for (int i = 1; i <= n + m + 1; i++) res += a[i];
    cout << res << endl;
    return 0;
  }
  sort(a + 1, a + n + m + 2);
  res = -a[1] + a[n + m + 1];
  for (int i = 2; i < n + m + 1; i++) res += abs(a[i]);
  cout << res << endl;
  return 0;
}
posted @ 2020-03-17 15:57  AdaMeta730  阅读(305)  评论(0)    收藏  举报