题目链接: Treasure
大致题意
给定一个字符串, 仅由’(’ ‘)’ ‘#’ 组成, 且至少包含一个’#’. 你可以在#处添加至少一个’)’. 要求序列中任何位置的前缀和中, '(‘的个数大于等于’)'的个数. 且最终括号匹配.
问能否对于每个#位置给出一种合法的放置个数, 使得满足题目要求. 若不能满足则输出-1.
解题思路
贪心, 很明显的贪心题目, 因为他要求①前缀和左≤右, ②最终序列匹配.
考虑到贪心做法, 我们不妨先假设每个#位置我们都只放1个右括号, 剩下差的括号, 我们都放在最后一个#位置. 那么在从前往后遍历的过程中, 如果出现了右括号多于左括号的情况, 一定不合法.
这样如果我们遍历完整个序列, 没有不合法的位置, 则我们一定存在一种放法, 使得对于任意位置, 左括号的数目≥右括号的数目. 接下来只需要看能否做到括号匹配即可.
而括号匹配的前提一定是左右括号的数目相等, 我们记pos为最后一个#出现的位置, 那么我们一定可以使得在#位置处再放置≥0个右括号, 使得左右括号数目相同.
但是此时出现了一个问题, 即我们有可能破坏对于任意位置左括号≥右括号这一性质.
我们不妨记录对于最后一个#, 最多还可以额外放last个右括号, 使得前缀和不被破坏.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
int main()
{
string s; cin >> s;
vector<int> res;
int num = 0; bool can = 1; int last = 0;
for (char & op : s) {
if (op == '(') num++;
else if (op == ')') num--;
else num--, res.push_back(1), last = num;
if (num < 0) can = 0;
}
if (!can or s.back() == '(') printf("-1\n");
else {
res.back() += num;
if (num > last) printf("-1\n");
else for (auto& op : res) printf("%d\n", op);
}
return 0;
}