问题描述
给定一个算术表达式形如1+3-5-4+6,表达式中的运算数全部都是正数,运算符全部是加号或者减号。
现在可以给算术表达式加任意多的括号,使得表达式的值最大。
如对于1+3-6-9+4-5-7+8,可以1+3-(6-9)+4-(5-7)+8,最优的方案是1+3-(6-9+4-5-7)+8
数据格式
T 例子个数
n1 第一个例子的运算数个数
1+3-6-9+4-5-7+8 算数表达式
n2
......
输出一个数字,表示表达式的最大值。
数据范围:运算数个数为1e5。
解析
- 最优答案中,括号只加在减号前面
- 最优答案中,若干个加号之间不加括号,例如3-4+5+6+7-8,其中5,6,7之间肯定没有括号
- 最优答案中,括号肯定不会嵌套
- 最优答案中,形如-a+b-c,如果c<b,那么-(a)+b-(c 比-(a+b-c 结果要好。
贪心的原则就是,既然无论如何都要给右面留下左括号,那么左括号的位置必然是最优的。
代码
#include<iostream>
using namespace std;
const int maxn = 1e5 + 7;
typedef long long ll;
int a[maxn];
char op[maxn];
int m;
int find(int ind) {
for (int i = ind; i < m; i++) {
if ( op[i] == '+' &&(i >= m - 1 || a[i + 1] < a[i])) {
return i-1;
}
}
return m - 1;
}
ll sum_range(int f, int t) {
ll s = 0;
for (int i = f; i <= t; i++) {
int value = (op[i] == '+' ? 1 : -1)*a[i];
s -= value;
}
return s;
}
ll solve() {
//压缩正号
int i = 0;
for (int j = 1; j < m; j++) {
if (op[j] == '+') {
if (op[i] == '+')
a[i] += a[j];
else {
i++;
op[i] = '+';
a[i] = a[j];
}
}
else {
i++;
op[i] = '-';
a[i] = a[j];
}
}
m = i + 1;
ll s = 0;
//如果我后面的负数比我大,我就要牺牲
for (int i = 0; i < m; i++) {
if (op[i] == '-') {
int j = find(i);
s += -a[i]+sum_range(i+1, j);
i = j;
}
else {
s += a[i];
}
}
return s;
}
int main() {
freopen("in.txt", "r", stdin);
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> m;
op[0] = '+';
for (int j = 0; j < m; j++) {
if (j > 0) {
cin >> op[j];
}
cin >> a[j];
}
cout << solve() << endl;
}
return 0;
}
原文地址:https://www.cnblogs.com/weiyinfu/p/9818616.html
时间: 2024-11-25 09:24:50