[Ceoi2016|BZOJ4936] Match

哈希+分治+stack


题目:

给你一个由小写字母组成的字符串s,要你构造一个字典序最小的(认为左括号的字典序比右括号小)合法的括号 
序列与这个字符串匹配,字符串和括号序列匹配定义为:首先长度必须相等,其次对于一对匹配的左括号和右括号 
i,j,必须有s[i]==s[j] 
无解输出-1

 

很坑:括号配对原来是最近的左括号右括号算一对...我以为随便怎么配只要左括号右括号数量相等且能左右分离就好了...

首先是判断无解情况:开一个stack,碰到和top相同的弹掉,如果最后stack不空就必然无解

 

然后是分治即可

显然对于Solve(l,r)的l元素的'('我们要找离其最远的')',当然这是要可行的前提下

难点是如何判断可行情况:在记录stack的情况下维护hash,出栈减掉,入栈加上,当Hash(l-1)==Hash(r)的时候(l,r)是可行区间

至于分治写起来就不难了

std好像是map,但是昨天写了一晚上的hash,就直接打hash了

而且用map在这里反而比hash要复杂!

代码:

 1 #include<bits/stdc++.h>
 2 #define ull unsigned long long
 3 using namespace std;
 4 inline int read(){
 5     int ans=0,f=1;char chr=getchar();
 6     while(!isdigit(chr)){if(chr=='-')f=-1;chr=getchar();}
 7     while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
 8     return ans*f;
 9 }const int M=1e5+5,B=131;
10 ull f[M],p[M],now;
11 char s[M],st[M],ans[M];
12 int top,n;
13 void Solve(int l,int r){
14     if(l>=r) return;
15     for(int p=r;;p--)
16         if(s[l]==s[p]&&f[l-1]==f[p]&&(p==r||f[p]==f[r])){
17             ans[l]='(',ans[p]=')';
18             Solve(l+1,p-1);
19             p<r?Solve(p+1,r):Solve(2,1);
20             break;
21         }
22 }
23 int main(){
24     freopen("match.in","r",stdin);
25     freopen("match.out","w",stdout);
26     scanf("%s",s+1);
27     n=strlen(s+1);
28     p[0]=1;
29     for(int i=1;i<=n;i++) p[i]=p[i-1]*B;
30     for(int i=1;i<=n;i++){
31         if(s[i]==st[top])    now-=p[top--]*(s[i]-'a'+1);
32         else now+=p[++top]*(s[i]-'a'+1),st[top]=s[i];
33         f[i]=now;
34     }if(top) return puts("-1"),0;
35     Solve(1,n);
36     printf("%s",ans+1);
37     return 0;
38 }

 

posted @ 2019-07-12 19:31  zheng_liwen  阅读(340)  评论(0编辑  收藏  举报
/*去广告*/