• 题解 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;
    }
    
  • 相关阅读:
    正则入门小随
    用栈求简单算术表达式的值
    数据结构复习
    数据结构笔记(第九章)
    数据结构笔记(第八章)
    Java第三阶段学习(十四、JSP动态页面、EL表达式、JSTL标签库)
    Java第三阶段学习(十三、会话技术、Cookie技术与Session技术)
    Java第三阶段学习(十二、HttpServletRequest与HttpServletResponse)
    Java第三阶段学习(十一、Servlet基础、servlet中的方法、servlet的配置、ServletContext对象)
    Java第三阶段学习(十、XML学习)
  • 原文地址:https://www.cnblogs.com/lsq147/p/16101940.html
Copyright © 2020-2023  润新知