1467: [蓝桥杯2019初赛]后缀表达式

题目

给定N 个加号、M 个减号以及N + M + 1 个整数A1,A2,...,AN+M+1。

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

请你输出这个最大的结果。

例如使用1 2 3 + -,则“2 3 + 1 -” 这个后缀表达式结果是4,是最大的。

思路

读完题后,觉得很常规很简单。最大值无非就是先排序,把从最大的那一头开始相加,最小的那一头相减即可。按照题目的例子测试了一下,发现也没啥问题,结果一提交就错误了。

很显然,我没有考虑到可以有括号出现的情况。例如:

1 2

1 2 3 4

=》4 + 3 - (1 - 2) = 4 + 3 + 2 - 1

相当于只有一个减号。此时的题目,要么就没有减法,要么减法只能为1。

同时,允许有负数存在!因此我们需要根据减法数目与总个数之间的关系进行讨论。

如果负数数目不等于总个数,则所有负数可以转换为正数(负负得正)。

如果负数的数目等于总个数,那么必然会剩下一个负数不能转换成正数。

  1. 有减法(只能为1次,也就是排序后的最小值)

    1. 有负数

      1. 负数数目不等于总数目

      2. 负数数目等于总数目(选择绝对值最小负数)

    2. 没有负数

  2. 没有减法

代码

 1//1467: [蓝桥杯2019初赛]后缀表达式
 2#include 
 3using namespace std;
 4int a[200010]; 
 5int main(){
 6    int N, M;
 7    cin>>N>>M; //N个加号,M个减号
 8    int num = N + M + 1;
 9    int num_fu = 0;  //统计负数的个数 
10    int sum = 0; 
11    for(int i = 0; i < num; i++){
12        cin>>a[i];
13        sum += a[i];
14        if(a[i] < 0) 
15            num_fu++;
16    }
17    sort(a, a + num);
18    if(M){
19        //如果有减法,需要对比总数目与负数数目
20        if(num_fu){
21            //如果有负数
22            if(num_fu == num){
23                //负数的数目与总目相等,则负负得正,sum等于所有数的绝对值之和 
24                for(int i = 0; i < num_fu - 1; i++){
25                    sum -= 2 * a[i]; //2倍是因为前面sum减过一次了
26                } 
27            } 
28            else{
29                //负数的数目与总数目不相等,则必有一个负数不能转换成正数
30                for(int i = 0; i < num_fu; i++){
31                    sum -= 2 * a[i];
32                } 
33            }
34        } 
35        else{
36            //如果没有负数,就只有一个负号起作用
37            sum -= 2 * a[0]; 
38        }
39    }
40    //如果没有减法,则最大值就直接是所有数的和
41    cout<

你可能感兴趣的:(1467: [蓝桥杯2019初赛]后缀表达式)