【题解】P8683 题解
P8683 题解
思路分析
由 个加号、 个减号以及 个整数凑出的合法后缀表达式。
贪心题。
看到“由 个加号、 个减号以及 个整数凑出”这一条件时,我们可以知道,题目要求我们用加减组成结果最大的式子。
看到“后缀表达式”这一条件,我们可以知道,凑出的式子还可以加括号,例如 1 2 + 3 4 - + 等于 (1+2)+(3-4)。
显然,结果可以表示为 (, 为整数),如果我们要让结果最大,那么我们就得使得 最小,于是可以取最小的数为 即可。
(注:为什么不用管最小的数的正负?如果最小数为负,那么很好,不减反加。如果是正的,那么刚好符合我们的要求。如果是零,啥事没有。)
接下来,我们就要让 最大。设原式为 。
此时剩下 个数。由于我们可以随意地添加括号,因此我们可以通过如下方法,使得 为余下的所有数的绝对值之和。
- 如果数为正数,则既可以添正号,放到 中,也可以添负号,放到 中。
- 如果数为负数,则既可以添负号,放到 中,也可以添正号,放到 中。
- 如果数为零,依照正数负数操作均可
接下来,我们证明:通过 个加号与 个减号,通过上述方式,一定可以让所有数变为其绝对值。
不妨设有 个正数与 个零。则负数个数 。
-
对负数操作,至少要 个正号, 个负号。
-
对正数操作,至少要 个正号, 个负号。
-
对零操作,至少要 个正号, 个负号。
-
共 个正号(有一个非负数可以不用正号), 个负号。
按照这种方式操作即可使得所有数变为其绝对值,而不用担心会不会加减号不够用。
于是最后直接排序操作即可。注意特判 的情况,这种情况不用找最小的数去减,直接全部相加。
代码
#include <iostream>
#include <algorithm>
#include <numeric>
#define int long long
using namespace std;
const int N = 2e5 + 10;
int a[N];
signed main()
{
int n, m;
cin >> n >> m;
for(int i = 1;i <= n + m + 1;i++)
{
cin >> a[i];
}
if(m == 0)
{
cout << accumulate(a + 1, a + n + m + 1 + 1, 0) << endl; //求和
}
else
{
sort(a + 1, a + n + m + 1 + 1); //排序
int ans = a[n + m + 1] - a[1]; //最大-最小
for(int i = 2;i <= n + m;i++)
{
ans += abs(a[i]); //绝对值之和
}
cout << ans << endl;
}
return 0;
}

浙公网安备 33010602011771号