每日一题---后缀表达式

在这里插入图片描述
这题其实主要涉及的是分类贪心的思想,而且这道题贪心的思路并不仅限于数字顺序的问题,还可以加括号,例如:
0 2
1 2 3
3−1−2=03−1−2=0 不对,3−(1−2)=43−(1−2)=4 正确
1 2
1 2 3 4
正确的顺序应该是 4+3−(1−2)=4+3+2−14+3−(1−2)=4+3+2−1
也就是说,最少可以只有一个减号起作用,其余的减号全部负负得正。

题目的数据范围里面可以有负数,后缀表达式实际上是隐藏括号的,我们也可借助这一特点来变负为正。
1 1
-3 -2 -1
(−2)+(−1)−(−3)(−2)+(−1)−(−3) 不对,实际情况应该是 (−1)−((−2)+(−3))(−1)−((−2)+(−3))
所以,这里我们要根据是否有负数存在以及负数和总个数的关系进行条件判断:
如果负数个数不等于总个数
3 3
-1 -1 2 2 2 2 2
可以写成 2+2+2−((−1)+2)−(−1)2+2+2−((−1)+2)−(−1)
最后负数全部能转换为正数
如果负数个数等于总个数
3 3
-2 -1 -1 -1 -1 -1 -1
应该是 (−1)−((−1)+(−1)+(−2)+(−1))−(−1)−(−1)(−1)−((−1)+(−1)+(−2)+(−1))−(−1)−(−1)
此时,因为一共有 n+mn+m 个正负号,n+m+1n+m+1 个数字,所以,必然有一个负数不能被转换为正数,根据贪心的理论,这个数字的绝对值应该最小,即负数最大。代码如下:

#include<bits/stdc++.h>
using namespace std;
int a[200020]; 
int main(){
	long long n,m,sum=0,z=0;
	cin>>n>>m;
	n=n+m+1;//正号的个数之后用不到 
	for(int i=0;i<n;i++){
		cin>>a[i];
		sum+=a[i];
		if(a[i]<0){
			z++;//统计负数的个数,方便后面进行判断 
		}
	}
	sort(a,a+n);//排序 
	if(m){//判断是否有负号,如果没有负号,那么最大值就是sum 
		if(z){//判断是否有负数 
			if(z==n){//判断负数个数和总个数的关系 
				for(int i=0;i<z-1;i++){//a[z-1]为最大值,即绝对值最小值 
					sum-=2*a[i];
				}
			}else{
				for(int i=0;i<z;i++){
					sum-=2*a[i];
				}
			}
		}else{
			sum-=2*a[0];
		}
	}
	cout<<sum<<endl;
	return 0;
}

其实这题主要是负数有点点麻烦,因为这样需要分情况讨论,根据负数个数来进行分类,比如
1 1
-3 -2 -1
如果按照我们开始的思路,这里的顺序就应该是
(-2)+(-1)-(-3)
但实际情况应该是
(-1)-((-2)+(-3))
所以这里我们要根据是否有负数存在已经负数和总个数关心进行条件判断
如果负数数量不等于于总个数
3 3
-1 -1 2 2 2 2 2
可以写成
2+2+2-((-1)+2)-(-1)
最后负数全部能转换为正数
如果负数数量等于总个数,
3 3
-2 -1 -1 -1 -1 -1 -1
-1-((-1)+(-1)+(-2)+(-1))-(-1)-(-1)
因为一共有m+n个正负号,但我有m+m+1个数字,所有必然有一个负数不能被转换为正数,根据贪心的理论,这个数字的绝对值应该最小,因为全为负数,等价于这个数字应该最大。
总的来说,虽然这题代码看着貌似不难,但分类考虑以及这里面的逻辑需要仔细斟酌才行,就思维量上来说这题通过还是比较不容易的。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值