#C231114B. 奇迹(miracle)


#C231114B. 奇迹(miracle)

标签(Label)

  • 思维
  • 图论转化

网址(Website)

题目详情 - 奇迹(miracle) - Super

题解 - 奇迹(miracle) - Super

P8227 「Wdoi-5」建立与摧毁的结界

题目(Problem)

题目背景

八云紫拥有操控境界程度的能力。作为其式神的八云蓝,同样拥有一定程度的操作境界的能力,而作为八云蓝的式神橙,却因为功力尚且不足,而无法对境界进行过多的干预了。

于是八云蓝打算教教橙,境界的用法。境界可以被抽象成一层一层的括号,操作境界本质上就是对括号序列进行修改。由于橙的能力尚且不足,因此只能进行一些简单的境界的建立与摧毁。

尽管如此,通过简单的操作,亦可以把一个境界转换为另外一个境界。为了给橙作为练习,蓝找来了两个境界的范本。将其中一个境界转换为另外一个境界的难度,就是橙需要施用能力的最小次数。但是由于境界实在太长,蓝决定写一个程序(?)来帮帮她计算出境界的难度。

题目描述

境界可以被抽象为由圆括号组成的括号序列。现做出如下定义:

  • 定义 $D_i$ 为嵌套括号序列。其中 $D_0$ 为零阶嵌套括号序列,被定义为单组括号 $\verb!()!$;而 $D_k$ 则为 $k$ 阶嵌套括号序列($k \geq 1$)定义为 $\verb!(!D_{k-1}\verb!)!$,即在 $D_{k-1}$ 的外层增添了一层括号。
  • 定义 $F_i$ 为平铺括号序列。其中 $F_0$ 为零阶平铺括号序列,被定义为单组括号 $\verb!()!$;而 $F_k$ 则为 $k$ 阶平铺括号序列($k \geq 1$),定义为 $\verb!()!F_{k-1}$,即在 $F_{k-1}$ 的左侧增添了一对括号。

例如,$\verb!((()))!$ 为 $D_2$,$\verb!()()()()!$ 为 $F_{3}$。

现在蓝给出了两个长度为 $n$ 的合法括号序列 $A$ 和 $B$。橙可以用以下操作对序列 $A$ 进行变换:

  • 选择任意非负整数 $k$,选择括号序列的一个子串满足其为一个 $k$ 阶嵌套括号序列,然后将其变为 $k$ 阶平铺括号序列。
  • 选择任意非负整数 $k$,选择括号序列的一个子串满足其为一个 $k$ 阶平铺括号序列,然后将其变为 $k$ 阶嵌套括号序列。

提示说明处有「合法括号序列」与「子串」的定义。

现在需要求出将序列 $A$ 变换为序列 $B$ 所需的最少操作数。可以证明,总存在一种操作方案能将序列 $A$ 变换为序列 $B$。

输入格式

  • 第一行共有一个整数 $n$,表示 $A$ 与 $B$ 括号序列的长度。
  • 接下来一行,共有 $n$ 个字符,描述括号序列 $A$。保证序列 $A$ 合法。
  • 接下来一行,共有 $n$ 个字符,描述括号序列 $B$。保证序列 $B$ 合法。

输出格式

  • 共一行,一个整数,表示将 $A$ 转换为 $B$ 需要的最少步数(可能为 $0$,也就是不进行任何操作)。

样例 #1

样例输入 #1

14
((()())(()()))
()()()()()()()

样例输出 #1

6

样例 #2

样例输入 #2

14
((()())(()()))
(()())(()())()

样例输出 #2

10

提示

选手目录下的 $miracle/miracle3 \sim5.in$ 与 $miracle/miracle3\sim 5.ans$。

样例 1 解释

  • 第一步:$\verb!((()())(()()))!\to\verb!(((()))(()()))!$。
  • 第二步:$\verb!(((()))(()()))!\to\verb!(((()))((())))!$。
  • 第三步:$\verb!(((()))((())))!\to\verb!(((()))()()())!$。
  • 第四步:$\verb!(((()))()()())!\to\verb!(()()()()()())!$。
  • 第五步:$\verb!(()()()()()())! \to\verb!((((((()))))))!$。
  • 第六步:$\verb!((((((()))))))!\to\verb!()()()()()()()!$。

可以证明,不存在更短的方案。

提示

合法括号序列通过这样一个形式定义:

  • $\verb!()!$ 是合法括号序列。
  • 若 $A$ 是合法括号序列,那么 $\verb!(!A\verb!)!$ 是合法括号序列。
  • 若 $A,B$ 均为合法括号序列,那么 $AB$ 是合法括号序列。

我们称 $A$ 是 $B$ 的子串,当且仅当删除 $B$ 开头若干个字符(可以不删除),再删除 $B$ 末尾若干个字符(可以不删除),剩下来的字符序列与 $A$ 完全相同。

数据范围及约定

本题共有 $20$ 个测试点,每个测试点 $5$ 分。最终分数为所有测试点分数之和。

本题使用打包测评。各子任务的附加限制及分值如下表所示:

子任务编号附加限制分值
$1$$n \leq 18$$15$
$2$$n \leq 2000$, 性质 $\mathrm{A}, \mathrm{B}$$20$
$3$$n \leq 2000$, 性质 $\mathrm{B}$$10$
$4$$n \leq 2000$$10$
$5$$n \leq 2 \times 10^{5}$, 性质 $\mathrm{B}$$10$
$6$$n \leq 2 \times 10^{5}$, 性质 $\mathrm{C}\qquad\quad$$10$
$7$无特殊限制$25$

特殊性质 $A$:保证 $B$ 是 $(n\div 2-1)$ 阶平铺括号序列。

题解(Solution)

$\qquad$由于作者很懒,感性理解就好啦~

代码(Code)

#include<bits/stdc++.h>
#include<stack>
#include<vector>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
inline int input(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;}
const int N = 1012345;
char s[N],t[N];
int n,ans;
vector<int> sona[N],sonb[N],*son;
int ra[N],rb[N];

inline void chai(int x){
	if(son[x].size()==0) return;
	while(son[x].size()==1) x=son[x][0];
	if(son[x].size()==0) return ans++,void();
	ans+=2;for(auto y:son[x]) chai(y);
}

void solve(int a,int b){
	for(int i=0,j=0;i<sona[a].size()||j<sonb[b].size();){
		if(i<sona[a].size()&&j<sonb[b].size() && sona[a][i]==sonb[b][j] && ra[sona[a][i]]==rb[sonb[b][j]]){//如果可以合成一个
			solve(sona[a][i],sonb[b][j]); 
			i++,j++;
		}else if(j==sonb[b].size() || (i<sona[a].size() && sona[a][i]<sonb[b][j])){
			son=sona;
			chai(sona[a][i]);
			i++;
		}else{
			son=sonb;
			chai(sonb[b][j]);
			j++;
		}
	}
}

signed main(){
	freopen("miracle.in","r",stdin);
	freopen("miracle.out","w",stdout);
	scanf("%d%s%s",&n,s+1,t+1);
	{
		int fa=0;stack<int> st;
		For(i,1,n){
			if(s[i]=='('){
				st.push(i);
				sona[fa].emplace_back(i);
				fa=i;
			}else{
				ra[st.top()]=i,st.pop();
				fa=st.empty()?0:st.top();
			}
		}
	}
	{
		int fa=0;stack<int> st;
		For(i,1,n){
			if(t[i]=='('){
				st.push(i);
				sonb[fa].emplace_back(i);
				fa=i;
			}else{
				rb[st.top()]=i,st.pop();
				fa=st.empty()?0:st.top();
			}
		}
	}
	solve(0,0);
	return cout<<ans<<'\n',0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录