后缀表达式

一、题目描述

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 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;	
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值