前言(闲唠)
这是一道蛮有意思的贪心题。
博主老早之前做过两次这道题,两次都没独立想出来。最近准备特长生考试复习到这道题,可算是基本想出来了,不过依旧很激动(因为之前怎么做的一点印象都没有了……),还是记录一下吧,估计以后还用得着(《第四次》)
正文
题面
给定
N
N
N 个加号、
M
M
M 个减号以及
N
+
M
+
1
N+M+1
N+M+1 个整数。
A
1
,
A
2
,
⋯
,
A
N
+
M
+
1
A_1,A_2,\cdots,A_{N+M+1}
A1,A2,⋯,AN+M+1,小明想知道在所有由这
N
N
N 个加号、
M
M
M 个减号以及
N
+
M
+
1
N+M+1
N+M+1 个整数凑出的合法的后缀表达式中,结果最大的是哪一个。
请你输出这个最大的结果。
思路
首先常规思路来讲,肯定是想优先加大的,再减去小的。
不过看数据范围有负数,而题面中是后缀表达式,这种思路就行不通了。因为有负号时,就有可能相当于是对带括号的加减混合算式拆括号,有负负得正的情况嘛。
那该如何利用这点解决这种情况呢?当然是通过变号,使得减去负数,加上正数啦。那接下来的问题就成了如何具体操作:
注意到,符号数量比数字数量少1,那必定有个数字没法改变符号,我们不妨把最大的数放这个位置。
那对于接下来的数,就想要:
①用加号
正数:加在外面
负数:加在前面有一个负号的括号里
②用负号
正数:减在前面有一个负号的括号里
负数:减在外面
这样,管它加号减号有多少就都可以搞了(好耶!)。但是!搞这样一个负号在括号前面就有一个数只能无符号放在括号最前面。因为是要被带着减去的,就选用最小的。
这样,问题就变为了最大值减最小值再加上其它数的绝对值。
代码实现
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=300010;
int n,m,a[N];
long long ans=0;
int main()
{
cin>>n>>m;
for(int i=1;i<=n+m+1;i++)
{
cin>>a[i];
}
sort(a+1,a+n+m+2);
if(m==0)
{
for(int i=1;i<=n+m+1;i++)
{
ans+=a[i];
}
}
else
{
ans=a[n+m+1]-a[1];
for(int i=2;i<=n+m;i++)
{
ans+=abs(a[i]);
}
}
cout<<ans;
return 0;
}
特判全是加号,排序,然后累加即可,注意long long。