题目描述
简单来说给你一串数字,这串数字可以是负数,n个加号和m个减号,问你怎么搭配能得到最大的值
解题思路
前略: 这题在我搞清楚前我觉得有点难的,然后我看了很多题解然后弄明白后发现是真的简单...再说之前我们必须要先明确一件事
后缀表达式是可以带括号的
即一般的后缀表达式23+1-其实是((2+3)-1)
简单来说题目有两种情况
- 没有负号的情况
这个情况最简单,直接全部加起来就行了 - 有负号的情况
这个时候我们需要想想,给你一串数字,怎么减才能得到最大的值呢?很简单,先排完序然后 {大的值} - {小的值} ,这样减出来的值就是最大的。
但是又因为这串数字可以是负数,我们可以先假设负号数目等于负数数目来思考,那么最大值减去最小值就可以化成 {正数} - {负数和正数} 即是 {正数} + {负数和正数的绝对值} 了
但是我们知道负号可以多于负数,我们可以看一串数字{1,2,3,4},负号有2个,正号1个,这时候我们的负号个数就是多于负数的,一般人会认为直接 (((4+3)-2)-1)=4 就行了,但这是错的,正确的是4-(1-(2+3))=8, 注意我的写法,我们可以通过将整数前面添加一个负号,然后把他放到一个带负号的括号里面,这样多余的负号就没有的,原来的正数也因为负负得正没有影响。
同理多出来的负数也可以把它放在一个带负数的括号里转化为整数
所以多余的负号可以人为的消去,多余的负数也可以人为转化为正数,那么可以简单认为负号的个数永远等于负数的个数 - 由上面的分析可以知道所求最大结果就是 最大值 - 最小值 + 剩余的绝对值 至于为什么要最大值减去最小值,只要假设全部为负号,最多也就是4-(1-2-3)而无法达到4-(-1-2-3)来解决.
分析完毕后,剩下的代码就简单了
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAX = 1e5+5;
LL num[2*MAX];
int main() {
int n,m;
scanf("%d %d",&n,&m);
int cnt=n+m+1;
for(int i=0;i<cnt;i++){
scanf("%lld",&num[i]);
}
LL sum=0;
if(m==0){//没有负号时
for(int i=0;i<cnt;i++)sum+=num[i];
printf("%lld\n",sum);
return 0;
}
//有负号时
sort(num,num+cnt);
//最大值减去最小值
sum+=num[cnt-1];
sum-=num[0];
//正数加上绝对值
for(int i=1;i<cnt-1;i++)sum+=abs(num[i]);
printf("%lld\n",sum);
return 0;
}