中缀表达式转换为后缀表达式的方法
以(2+3)*5为例:
①将所有运算按照优先级加上小括号,得到:((2+3)*5)
②将运算符移到对应小括号后,得到:( ( 2 3 ) + 5 ) *
③去掉小括号,得到:2 3 + 5 *
分析:
如果M=0,即没有减号,易知,N+1个数相加的结果是确定的,因此, 最大值就是输入的N+1个数的和
以下讨论都是针对M>0的情形,即至少有一个减号
输入的是后缀表达式, 没有括号, 但等价的中缀表达式, 可能有括号
例如,后缀表达式2 3 5 + -,等价的中缀表达式是:2-(3+5)
本题只有+和-,而-号在括号前可以把括号内的所有加号或减号进行取反,例如:
a-(b +c+d+e)=a-b-c-d-e,将3个加号变为负号
a-(b-c-d-e)=a-b+c+d+e,将3个减号变为正号
a-(b +c)-(d+e)=a-b-c-d-e,括号前的-号都把括号内的符号取反
a-(b-c)-(d-e)=a-b+c-d+e,括号前的-号都把括号内的符号取反
因此, 虽然输入N+M+1个数,原本有N个+号,M个-号,但可以转变成任意X个加号、Y个减号,其中X,Y满足X+Y==N+M,X≥0,Y≥1,即至少有一个减号
题目没有要求输入的N+M+1个数必须严格按输入顺序出现在后缀表达式中,这就意味着为了使得表达式的取值最大, 可以将这些数任意组合,比如几个负数先在括号内加起来,括号前面再放一个减号
但是,转换以后的表达式最前面的操作数无法改变符号,且至少有一个减号。所以最后的结果为:N+M+1个数中,一个数不改变符号、一个数加上负号取反、其他数可取绝对值,容易看出不改变符号的数应该选最大值,取反的数应该选最小值,这时表达式的值最大。对输入的N+M+1个数排序即可实现
用向量存储输入的N+M+1个数。 对向量进行排序和求和都是非常方便的
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
int main(){
int i, N, M;
cin >> N >> M;
vector<int> v(N+M+1);
for(i=0;i<N+M+1;i++) cin >> v[i];
if(M==0){
cout << accumulate(v.begin(), v.end(), 0LL) << endl;
return 0;
}
sort(v.begin(), v.end()); //从小到大排序
LL ans = v[N+M+1-1] - v[0];
for(i=1;i<N+M;i++) ans += abs(v[i]);
cout << ans << endl;
return 0;
}