您的位置:首页 > 其它

[bzoj4936]Match

2017-08-16 17:37 218 查看

题目大意

给你一个小写字母字符串。

请构造一个合法括号序,使得匹配的括号在原串中字母相同。

要求字典序最小,且要求判断无解。

暴力

我们考虑如何判断无解。

你考虑一个栈,顺序扫这个字符串。

假如当前字符和栈顶字符相同消除栈顶字符,否则将这个字符加进栈中。

这可以得到一个合法解,且我们可以证明任意解可以变成这个合法解。

这就是无解判断。

字典序最小的暴力也很简单。

一些性质

我们设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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: