题解 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;
}