bzoj 4936: [Ceoi2016]match hash+构造
2017-09-17 20:42
344 查看
题意
给你一个由小写字母组成的字符串s,要你构造一个字典序最小的(认为左括号的字典序比右括号小)合法的括号序列与这个字符串匹配,字符串和括号序列匹配定义为:首先长度必须相等,其次对于一对匹配的左括号和右括号i,j,必须有s[i]==s[j]。无解输出-1n<=100000
分析
一道脑洞比较大的题。设f[i,j]=0/1表示[i,j]这一段是否能组成一个合法的括号序。
首先考虑如何判-1。我们可以把元素逐个放入一个栈内,若栈顶两个元素相同则出栈。显然若最后栈不为空则必然没有合法方案,反之则必然存在合法方案。
我们设hash[i]表示把前i个元素放入栈后那个栈的hash值。
显然若f[i,j]==1则必有hash[i-1]==hash[j]
我们设过程solve(l,r)表示给[l,r]这一段构造一个字典序最小的方案。显然l一定是左括号,设l匹配的位置为pos,那么有pos={max(x)|s[x]==s[l]且f[x+1,r]==1}
由于f[x+1,r]==1等价于hash[x]==hash[r],也就是说我们要找到一个最大的x满足s[x]==s[l]且hash[x]==hash[r]。
问题在于如何找pos。我们可以用map来维护一个指针,然后先递归solve(pos+1,r),这样的话所有的指针都移到了[l,pos],然后再递归solve(l+1,pos-1)即可。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> using namespace std; typedef long long LL; const int N=100005; const int MOD1=1000000007; const int MOD2=998244353; int n,mi1 ,mi2 ,sta ,top,lef ,ans ,s ; pair<int,int> hash ; map<pair<int,int>,int> w[27]; char ch ; void solve(int l,int r) { if (l>r) return; ans[l]=1; int pos=w[s[l]][hash[r]]; while (ans[pos]) pos=lef[pos]; w[s[l]][hash[r]]=lef[pos]; ans[pos]=2; solve(pos+1,r);solve(l+1,pos-1); } int main() { scanf("%s",ch+1); n=strlen(ch+1); for (int i=1;i<=n;i++) s[i]=ch[i]-'a'+1; mi1[0]=mi2[0]=1; LL now1=0,now2=0; for (int i=1;i<=n;i++) { mi1[i]=(LL)mi1[i-1]*26%MOD1; mi2[i]=(LL)mi2[i-1]*26%MOD2; if (top&&s[sta[top]]==s[i]) { (now1-=(LL)mi1[top-1]*s[sta[top]])%=MOD1; (now2-=(LL)mi2[top-1]*s[sta[top]])%=MOD2; if (now1<0) now1+=MOD1; if (now2<0) now2+=MOD2; top--; } else { sta[++top]=i; (now1+=(LL)mi1[top-1]*s[i])%=MOD1; (now2+=(LL)mi2[top-1]*s[i])%=MOD2; } hash[i]=make_pair((int)now1,(int)now2); lef[i]=w[s[i]][hash[i]]; w[s[i]][hash[i]]=i; } if (hash .first||hash .second) { puts("-1"); return 0; } solve(1,n); for (int i=1;i<=n;i++) putchar(ans[i]==1?'(':')'); return 0; }
相关文章推荐
- BZOJ 4936: [Ceoi2016]match
- bzoj 4936: [Ceoi2016]match
- BZOJ 4934: [Ceoi2016]kangaroo
- BZOJ 4937: [Ceoi2016]popeala
- 【BZOJ4523】【CQOI2016】路由表 Trie
- bzoj4561: [JLoi2016]圆的异或并
- 【bzoj4580】[Usaco2016 Open]248 区间dp
- bzoj 4515: [Sdoi2016]游戏(树链剖分+线段树)
- bzoj 3341: [Ceoi2013]adriatic 动态规划
- [BZOJ4539][HNOI2016]树-虚树
- bzoj4542: [Hnoi2016]大数
- 【BZOJ 4455】【UOJ #185】【ZJOI 2016】小星星
- 【bzoj4542】[Hnoi2016]大数 莫队
- bzoj 4540: [Hnoi2016]序列
- bzoj 4653: [Noi2016]区间 (线段树)
- 【BZOJ4852】【JSOI2016】炸弹攻击
- [bzoj4540][Hnoi2016]序列 莫队+RMQ
- bzoj 4521: [Cqoi2016]手机号码 数位dp
- bzoj4720 [Noip2016]换教室
- [BZOJ4455][ZJOI2016]数星星(容斥DP)