[bzoj4936]Match

来源:互联网 发布:网络支付公司 编辑:程序博客网 时间:2024/06/06 14:16

题目大意

给你一个小写字母字符串。
请构造一个合法括号序,使得匹配的括号在原串中字母相同。
要求字典序最小,且要求判断无解。

暴力

我们考虑如何判断无解。
你考虑一个栈,顺序扫这个字符串。
假如当前字符和栈顶字符相同消除栈顶字符,否则将这个字符加进栈中。
这可以得到一个合法解,且我们可以证明任意解可以变成这个合法解。
这就是无解判断。
字典序最小的暴力也很简单。

一些性质

我们设f(l,r)=0/1表示只看l~r是否合法。
我们设s[i]表示将1~i加入栈中后栈内元素情况(用哈希值表示)。
则f(l,r)=1一定要有s[l-1]=s[r]。
我们用过程solve(l,r)表示想要给l~r构造最小字典括号序。
我们需要知道谁和l匹配。
假设为pos。
那么pos=max{x|a[x]=a[l]且f(x+1,r)=1}
然后继续递归solve(pos+1,r)和solve(l+1,pos-1)
如何找到pos成为了问题。
发现f(x+1,r)=1就是s[x]=s[r]。
对于同一哈希值同一字符,它显然是单调的,也就是这个pos在减小。
然后如果我们优先solve(pos+1,r),就可以让所有的指针都到[l,pos],于是继续递归solve(l+1,pos-1)。
然后我们就线性解决了本题。

#include<cstdio>#include<algorithm>#include<cstring>#include<map>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;typedef pair<int,int> pi;map<pi,int> p[30];const int maxn=100000+10,mo1=1000000007,mo2=998244353;char s[maxn],ans[maxn];int sta[maxn],left[maxn],mi[maxn][2];pi sum[maxn];int i,j,k,l,t,n,m,tot,top,now1,now2;void solve(int l,int r){    if (l>r) return;    ans[l]='(';    int pos=p[s[l]-'a'][sum[l-1]];    while (ans[pos]=='('||ans[pos]==')') pos=left[pos];    p[s[l]-'a'][sum[l-1]]=left[pos];    ans[pos]=')';    solve(pos+1,r);    solve(l+1,pos-1);}int main(){    freopen("data.in","r",stdin);freopen("wzd.out","w",stdout);    scanf("%s",s+1);    n=strlen(s+1);    mi[0][0]=mi[0][1]=1;    fo(i,1,n){        mi[i][0]=(ll)mi[i-1][0]*27%mo1;        mi[i][1]=(ll)mi[i-1][1]*27%mo2;    }    now1=now2=0;    sum[0]=make_pair(0,0);    fo(i,1,n){        if (top&&s[sta[top]]==s[i]){            (now1-=(ll)(s[sta[top]]-'a'+1)*mi[top-1][0]%mo1)%=mo1;            (now1+=mo1)%=mo1;            (now2-=(ll)(s[sta[top]]-'a'+1)*mi[top-1][1]%mo2)%=mo2;            (now2+=mo2)%=mo2;            top--;        }        else{            (now1+=(ll)(s[i]-'a'+1)*mi[top][0]%mo1)%=mo1;            (now2+=(ll)(s[i]-'a'+1)*mi[top][1]%mo2)%=mo2;            sta[++top]=i;        }        sum[i]=make_pair(now1,now2);    }    if (top){        printf("-1\n");        return 0;    }    fo(i,1,n){        //if (i){            left[i]=p[s[i]-'a'][sum[i]];            p[s[i]-'a'][sum[i]]=i;        //}    }    solve(1,n);    fo(i,1,n) printf("%c",ans[i]);}