A1/2/3 Balanced Unshuffle

A1

A2

A3

这个是比赛中我为队贡献的最有价值的一题,写一下吧。以下就是我的思考过程。

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;
}
posted @ 2024-05-06 20:51  SFlyer  阅读(21)  评论(0编辑  收藏  举报