题意
给一个包含'(',')','?'
的串,需要在'?'
处填'('或')'
,使其满足
- 每个严格前缀(严格前缀 指不是整个串的所有前缀)不是可匹配的括号序列
- 整个串是可匹配的括号序列
无法构造输出:(
题解
其实就是构造一个首尾对应的括号序列。
那么把第一个和最后一个排除了,把中间的那些构造成一个合法的括号序列就行了。
至于怎么构造,使用贪心:
- 首先先将能匹配的
'('和')'
给匹配了,并且尽量相近的匹配。 - 然后用
'?'
位来补'('和')'
剩下的。 - 最后剩余的
'?'
位自己匹配自己。
最后判定一下这样构造出来的括号序列合不合法(如果不合法就说明构造不出来)即可。
好像写复杂了...看了一下别人的构造方法都很简短...
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 300010;
int n, top;
char s[N];
bool vis[N];
int id[N];
int main() {
scanf("%d", &n);
scanf("%s", s + 1);
if(s[1] == ')' || s[n] == '(') return puts(":("), 0;
s[1] = '('; s[n] = ')';
int cur = 1, tot = 0;
for(int i = 2; i < n; ++i) if(s[i] == ')') id[++tot] = i;
for(int i = 2; i < n; ++i) {
if(s[i] == '(') {
if(cur <= tot) {
vis[id[cur]] = 1;
vis[i] = 1;
++cur;
}
}
if(id[cur] == i) ++cur;
}
cur = n - 1;
for(int i = 2; i < n; ++i) {
if(s[i] == '(' && !vis[i]) {
while(cur > 1 && ( s[cur] != '?' || (s[cur] == '?' && vis[cur]) ) )
--cur;
if(s[cur] == '?' && !vis[cur])
vis[cur] = 1, s[cur] = ')', vis[i] = 1;
}
}
cur = 2;
for(int i = n - 1; i > 1; --i) {
if(s[i] == ')' && !vis[i]) {
while(cur < n && ( s[cur] != '?' || (s[cur] == '?' && vis[cur] ) ) ) ++cur;
if(s[cur] == '?' && !vis[cur]) vis[cur] = 1, s[cur] = '(', vis[i] = 1;
}
}
bool flag = 0;
top = 0;
for(int i = 2; i < n; ++i) {
if(s[i] == '?' && !vis[i]) {
s[i] = flag ? ')' : '(';
flag ^= 1;
}
}
for(int i = 1; i <= n; ++i) {
if(s[i] == '(') ++top;
else --top;
if(top <= 0 && i != n) return puts(":("), 0;
}
if(top != 0) return puts(":("), 0;
puts(s + 1);
}