这个是比赛中我为队贡献的最有价值的一题,写一下吧。以下就是我的思考过程。
A1
别人做的。但是签到,略。
A2, A3
因为 A2, A3 方法差不多,就直接说 \(\mathcal{O}(n)\) 的做法。
我们来研究一个例子 ((()))()(())
。他的前驱为 ((()()))()()
。
我们能得到的消息有,Prefix balance(PB) 为 \(0\) 的有 \(3\) 个,因为 ((()))()(())
开头有 \(3\) 个 (
。(为什么呢?因为 )
显然 PB\(\ge 1\),而且如果是小于 \(3\) 个,一定会先出现一个 )
,他是倒序排的)。所以,我们知道前驱是 (...)(...)(...)
这样的一个东西。
有 \(3\) 个 (
,一定会对应三个 )
,所以 ((()))()(())
中的 \(4\) 到 \(6\) 都是 PB 为 \(1\) 的。怎么确定第 \(7\) 个呢?同样,如果 PB 为 \(2\),一定是 )
。所以,第 \(7\) 个 PB 为一。所以,我们知道前驱是 ((...)(...)(...)
这样的一个东西。
第 \(8\) 个告诉我们是 ((...))(...)(...)
这样的一个东西。类似的,第 \(9,10\) 个告诉我们是 ((...(...(...))(...)(...)
这样的一个东西。最有两个,根据 PB 的值,我们就得到 ((()()))()()
了!
这只是一个例子。我们怎么用具体描述?
按照 PB 把 ((()))()(())
分类,有 (((
是 \(0\),)))(
是 \(1\),)((
是 \(2\),))
是 \(3\)。我们可以发现,对于 PB 是 \(i+1\) 的,塔里面的 )
数量是 \(i+1\) 里的 (
数量。)
够了,要一直加到不是 (
为止。我们就求出哪些括号是什么 PB 了。
上面的东西,我们把 \(i+1\) 中的 )
移到 \(i\) 里面,我们得到了:((()))
,()
,(())
,这说明,是 ()()()
,()
,()()
逐层嵌套的形式。因为是 PB 相同的时候按照从大到小的编号,所以,约在后的要嵌套到前面。比如说,()()
嵌套在 ()
里,变成 (()())
。因为是 )))(
,所以 (()())
应该嵌套在 ()()()
的第一个里面,变成了 ((()()))()()
!
具体是第几个,就是 reverse 后前面有多少个 )
加一个。很好理解。因此我们把嵌套的连一条边然后 dfs 就可以 \(\mathcal{O}(n)\) 做完了。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e5+5;
string s;
vector<string> v;
vector<int> g[N],e[N];
int cnts[N],id[N];
void dfs(int u){
if (e[u].size()==0){
cout<<"()";
return;
}
if (u) cout<<"(";
for (auto v : e[u]){
dfs(v);
}
if (u) cout<<")";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>s;
int i=0;
string cur;
while (s[i]=='('){
cur.push_back('(');
i++;
}
v.push_back(cur);
int cnt=cur.size();
cur.clear();
while (i<s.size()){
int ct=0,cc=0;
while (ct<cnt){
ct+=(s[i]==')');
cc+=(s[i]=='(');
cur.push_back(s[i]);
i++;
}
while (i<s.size() && s[i]=='('){
cc++;
cur.push_back(s[i]);
i++;
}
v.push_back(cur);
cur="";
cnt=cc;
}
for (int i=0; i<v.size(); i++){
reverse(v[i].begin(),v[i].end());
}
for (int i=0; i+1<v.size(); i++){
int cl=0;
for (auto ch : v[i]){
cl+=(ch=='(');
}
cnts[i]=cl;
}
for (int i=0; i<cnts[0]; i++){
e[0].push_back(i+1);
}
id[0]=1;
int sum=cnts[0];
for (int i=1; i+1<v.size(); i++){
id[i]=sum+1;
sum+=cnts[i];
}
for (int i=0; i+1<v.size(); i++){
int cur=0,cnt=0;
for (auto ch : v[i+1]){
if (ch=='('){
e[id[i]+cur].push_back(id[i+1]+cnt);
cnt++;
}
else{
cur++;
}
}
}
dfs(0);
return 0;
}
标签:PB,cur,...,int,A1,嵌套,Balanced,Unshuffle
From: https://www.cnblogs.com/SFlyer/p/18175867