试题 I: 后缀表达式
时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
给定 N 个加号、M 个减号以及 N + M + 1 个整数 A1, A2, · · · , AN+M+1,小
明想知道在所有由这 N 个加号、M 个减号以及 N + M + 1 个整数凑出的合法的
后缀表达式中,结果最大的是哪一个?
请你输出这个最大的结果。
例如使用1 2 3 + -,则 “2 3 + 1 -” 这个后缀表达式结果是 4,是最大的。
【输入格式】
第一行包含两个整数 N 和 M。
第二行包含 N + M + 1 个整数 A1, A2, · · · , AN+M+1【输出格式】
输出一个整数,代表答案。
【样例输入】
1 1
1 2 3
【样例输出】
4
【评测用例规模与约定】
对于所有评测用例,0 ≤ N, M ≤ 100000,ˈ 109 ≤ Ai ≤ 109。
分析:
/为了便于处理表达式,常常将普通表达式(称为中缀表示)
转换为后缀{运算符在后,如X/Y写为XY/表达式。
在这样的表示中可以不用括号即可确定求值的顺序,
如:(P+Q)(R-S) → PQ+RS-*。后缀表达式的处理过程如下:
扫描后缀表达式,凡遇操作数则将之压进堆栈,
遇运算符则从堆栈中弹出两个操作数进行该运算,将运算结果压栈,然后继续扫描,
直到后缀表达式被扫描完毕为止,此时栈底元素即为该后缀表达式的值。
解题思路:
①减号个数为0,那么没有办法只能全加
②减号个数等于负数个数,那么减去所有负数就能得到最大结果
③减号个数小于负数个数,可以通过加号的补充来达到上一种情况的效果的
比如(6 5 -4 -3 -2 -1),有1个减号,那么可以变成 6 + 5 - ( -4 + -3 + -2 + -1 ) ;有2个减号,那么可以变成 6 + 5 - -4 - ( -3 + -2 + -1 ) ;有3个减号,那么可以变成6 + 5 - -4 - -3 - ( -2 + -1 )
④减号个数大于负数个数,分两种情况,第一种全是正数的情况,就减掉最小的数然后进行相加。第二种存在负数的情况,就把所有数的绝对进行相加
例如:输入2 4
-1 -2 -3 4 5 6 7
可以这样组合:4-((-3)-7-2)+5+6 -(-1)
输入0 4
5 - (1-2-3-4) = 5+4+3+2-1 = 13
综上所述,第一种是直接求和,第二种和第三种是可以合并的,即求绝对值和。
/*为了便于处理表达式,常常将普通表达式(称为中缀表示)
转换为后缀{运算符在后,如X/Y写为XY/表达式。
在这样的表示中可以不用括号即可确定求值的顺序,
如:(P+Q)*(R-S) → PQ+RS-*。后缀表达式的处理过程如下:
扫描后缀表达式,凡遇操作数则将之压进堆栈,
遇运算符则从堆栈中弹出两个操作数进行该运算,将运算结果压栈,然后继续扫描,
直到后缀表达式被扫描完毕为止,此时栈底元素即为该后缀表达式的值。
解题思路:
①减号个数为0,那么没有办法只能全加
②减号个数等于负数个数,那么减去所有负数就能得到最大结果
③减号个数小于负数个数,可以通过加号的补充来达到上一种情况的效果的
比如(6 5 -4 -3 -2 -1),有1个减号,那么可以变成 6 + 5 - ( -4 + -3 + -2 + -1 ) ;有2个减号,那么可以变成 6 + 5 - -4 - ( -3 + -2 + -1 ) ;有3个减号,那么可以变成6 + 5 - -4 - -3 - ( -2 + -1 )
④减号个数大于负数个数,分两种情况,第一种全是正数的情况,就减掉最小的数然后进行相加。第二种存在负数的情况,就把所有数的绝对进行相加
综上所述,第一种是直接求和,第二种和第三种是可以合并的,即求绝对值和。
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class test9 {
public static void main(String[] args) throws IOException{
int[] positive = new int[100000+1]; //储存正数的数组,int的取值范围2147483648
int[] negative = new int[100000+1];
int po = 0; //正数的个数
int ne = 0; //负数的个数
int n = 0; //正号的个数
int m = 0; //负号的个数
long sum = 0;
n = MyReader.nextInt();
m = MyReader.nextInt();
for(int i=0; i<n+m+1; i++){ //读取数据
int temp = MyReader.nextInt();
if(temp>0) positive[po++] = temp;
else negative[ne++] = temp;
}
if(m<=0){ //负号的个数小于零, 将所有的数进行相加
for(int i=0; i<po; i++){
sum = sum + positive[i];
}
for(int i=0; i<ne; i++){
sum = sum + negative[i];
}
}
if(m<=ne&&m>0){ //负号的个数小于等于负数的个数,求绝对值和。
for(int i=0; i<po; i++){
sum = sum + positive[i];
}
for(int i=0; i<ne; i++){
sum = sum + Math.abs(negative[i]);
}
}
if(m>ne){ //负号的个数大于负数的个数,先求和再减去多余负号个数的小正数。
Arrays.sort(positive,0,po); //将数组进行排序,默认是正序
//不能写成Arrays.sort(a),因为这是对整个数组进行排序。数组中有很多是无效的零,
//因为定义的时候将数组的大小设定为题目给的大上限值。默认值都是零
if(ne==0){ //全是正数,减掉最小的数,把其他数的绝对值进行相加
sum = sum - positive[0];
for(int i=1; i<po; i++){ //将剩下的正数进行相加
sum = sum + positive[i];
}
for(int i=0; i<ne; i++){
sum = sum + Math.abs(negative[i]);
}
}
else{ //存在负数, 将所有数的绝对值进行相加
for(int i=0; i<po; i++){
sum = sum + positive[i];
}
for(int i=0; i<ne; i++){
sum = sum + Math.abs(negative[i]);
}
}
}
System.out.println(sum);
}
}
class MyReader{
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));//定义字符流
static StringTokenizer tokenizer = new StringTokenizer("");
static String nextLine() throws IOException{// 读取下一行字符串
return reader.readLine();
}
static String next() throws IOException {// 读取下一个字符串
while (!tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {// 读取下一个int型数值
return Integer.parseInt(next());
}
static double nextDouble() throws IOException {// 读取下一个double型数值
return Double.parseDouble(next());
}
}