I.后缀表达式
题目描述:
给定 N 个加号、M 个减号以及 N+M+1 个整数 A1,A2,⋅⋅⋅,AN+M+1,小明想知道在所有由这 N 个加号、M 个减号以及 N+M+1 个整数凑出的合法的后缀表达式中,结果最大的是哪一个?
请你输出这个最大的结果。
例如使用 123+−,则 “23+1−” 这个后缀表达式结果是 4,是最大的。
输入格式
第一行包含两个整数 N 和 M。
第二行包含 N+M+1 个整数 A1,A2,⋅⋅⋅,AN+M+1。
输出格式
输出一个整数,代表答案。
数据范围
0≤N,M≤105,
−109≤Ai≤109
输入样例:
1 1
1 2 3
输出样例:
4
后缀表达式又称逆波兰表达式:
形如 : 1 2 3 4 + + + 2 1 - + 等价于 { 1 + [ 2 + (3 + 4 )] } + (2 - 1 )= 11
本题给n个加号,m个减号,n+m+1个数,任意搭配后缀表达式,使得求出的后缀表达式值最大。
题解:
策略:要想使后缀表达式值最大,我们采取"加正数,减负数"的方案。
1.如果没有减号,我们直接把n+m+1个数加和就是最大值。
2.如果有减号,我们先对n+m+1个数进行排序。选取一个最大值Ai,选取一个最小值Aj,再拿出一个减号,表示为: Ai - ( Aj**)** [这里得小括号是后缀表达式转中缀表达式可以加的小括号]。
下面分类讨论(我们只需要讨论减号和负数的关系):
-
如果减号与负数的个数相同 :直接把减号和负数全部放到小括号外面,正数和加号也放到小括号外面。比如:1+ 2 + 3-(-1)-(-2)-(-3 )[最后一个小括号是我们上面写的小括号-( Aj)]
-
如果减号的个数小于负数的个数:把全部减号与负数搭配放到小括号外面,剩下的负数与加号搭配放到小括号里面。比如:1+ 2 + 3-(-1)-(-2)-( -3 + (-2) + (-1) ) [最后一个小括号是我们上面写的小括号-( Aj)]
-
如果减号的个数大于负数的个数:把全部负数与减号搭配放到小括号外面,剩下的减号和正数搭配放到小括号里面。比如:1+ 2 + 3-(-1)-(-2)-( -3 - 2 - 1 ) [最后一个小括号是我们上面写的小括号-( Aj)]
总结:如果我们想求取最大值,以上的3种情况都可以表示为拿出一个最大数,拿出一个最小数,让最大数-最小数,然后其他数都加上它们的绝对值。
满分代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const ll N=1e6+10;
ll a[N];
int main()
{
ll n,m,k;
cin>>n>>m;
ll sum=0;
for(int i=0;i<n+m+1;i++) cin>>a[i];
if(!m)
{
for(int i=0;i<n+m+1;i++)
sum+=a[i];
}
else
{
sort(a,a+m+n+1);
sum+=a[n+m];
sum-=a[0];
for(int i=1;i<n+m;i++)
sum+=abs(a[i]);
}
cout<<sum<<endl;
return 0;
}