题解 P8227

题解 P8227

闲话:离高考还有六十几天的时候打了下你古的普及组模拟赛,然后写了下这道题,发现自己思维还没退化到那种程度(

考虑一个合法括号串,其中第一个字符(是和最后一个字符)匹配的,那么如何才能改变第一个字符匹配的位置呢?

不难发现,只有先把括号串变成((((....))))这样才有可能花费一步把它变成()()....()(),也才有可能改变第一个字符的匹配位置。

需要注意的是,这个操作是必须的,也就是说只要你想改变第一个字符的匹配位置,你就必须先把它变成((((....)))),再变成()()....()()

考虑到两种变换是互逆的,所以可以将题目转变成将A,B串都变换成一个C串,最小化两次变换操作之和。

先将A,B串分成几个大部分,举个例子(下面列出的是两两匹配的字符):

(....)(..)(......)()()
(..)(....)(......)(..)

考虑A串的第一个部分(....)与下面B串并不对应,所以第一个字符的匹配是必须要变的,于是变成:

()()()(..)(......)()()
(..)(....)(......)(..)

同样的,B串下面的第一个大部分也是必须要变的:

()()()(..)(......)()()
()()(....)(......)(..)

一步一步如是操作:

()()()()()(......)()()
()()()()()(......)(..)

此时出现了两个对应的大部分(......)(......),于是这两个部分我们可以不将其全部拆解,保留最外层的两个匹配括号,然后递归处理中间部分。

一步一步执行如上操作即可,不难发现每次操作都是必须的,这保证了最小操作次数。

剩下的问题就是如何将一个括号串(..........)变成((((....))))再变成()()....()()

其实很简单,一步一步剥开外层括号,再将剩下的括号拆成几大部分递归处理即可。

总时间复杂度 \(O(n)\)

代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
	static char c;static int f;
	for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
	for(x=0;c>='0'&&c<='9';c=ch()){x=x*10+(c&15);}x*=f;
}
template<typename T>void write(T x){
	static char q[64];int cnt=0;
	if(x==0)return pc('0'),void();
	if(x<0)pc('-'),x=-x;
	while(x)q[cnt++]=x%10+'0',x/=10;
	while(cnt--)pc(q[cnt]);
}
const int maxn=1000005;
int ans;
void spread(int*s,int l,int r){
	if(l+1==r)return;
	while(l<r&&s[l]==r)++l,--r;if(l<r)++ans;
	while(l<r)spread(s,l,s[l]),l=s[l]+1;++ans;
}
char A[maxn],B[maxn];
int mA[maxn],mB[maxn];
void divide(int l,int r){
	int a=l,b=l;
	while(a<=r||b<=r){
		if(a<r&&(b>r||a<b||mA[a]<mB[b])){
			spread(mA,a,mA[a]);
			a=mA[a]+1;
		}
		else if(b<r&&(b>r||b<a||mB[b]<mA[a])){
			spread(mB,b,mB[b]);
			b=mB[b]+1;
		}
		else{
			divide(a+1,mA[a]-1);
			a=mA[a]+1;
			b=mB[b]+1;
		}
	}
}
int main(){
	int n;read(n);
	scanf("%s",A+1);
	scanf("%s",B+1);
	for(int i=1;i<=n;++i){
		mA[i]=mB[i]=i;
		while(A[mA[i]]==')')
			mA[i]=mA[mA[i]]-1;
		mA[mA[i]]=i;
		while(B[mB[i]]==')')
			mB[i]=mB[mB[i]]-1;
		mB[mB[i]]=i;
	}
	divide(1,n);
	write(ans),pc('\n');
	return 0;
}
posted @ 2022-04-05 12:48  xiaolilsq  阅读(78)  评论(0编辑  收藏  举报