题面
温神不喜欢括号序列,但是他发现总是有人喜欢出括号序列的题。
为了让全世界都能感受到他的痛苦,他想要写一个转换器:它能把普通的小写字符串转换成长度相同的合法的括号序列。
在温神的构思中,这样的转换器需要满足如下两个条件:
- 结果的括号序列必须要是合法的,即左右括号必须要是相匹配的。
- 对于一对相匹配的左右括号,他们所在的位置原来的小写字母必须相同。
举例来说,对于字符串 aabaab
,()(())
就是一个合法的答案,而 ()()()
不满足第二个条件,(((())
不满足第一个条件。
温神发现,不是对于所有的小写字符串,都存在满足条件的转化方案。于是她给出了一个字符串 s,她想要知道有多少个区间 [l,r],满足区间 [l,r] 形成的字符串存在每组条件的转化方案。
对于 20% 的数据,|s|≤20。 对于 40% 的数据,|s|≤500。 对于 70% 的数据,|s|≤5000。 对于 100% 的数据,|s|≤1e6。
分析
dp或者最简单的用栈模拟,都可以搞70分
然而正解是字符串哈希,我们可以观察发现,当[1,i]的栈内序列等于[1,j]的栈内序列的时候,说明[i+1,j]是合法的,同理如果[1,k]也等于[1,i]时的,那么[k,j]的区间也是合法的。
所以用双哈希存一下,Map映射一下记录出现次数
代码
#include<bits/stdc++.h> using namespace std; #define N 1000010 typedef long long ll; char s[N],sta[N]; ll top=0,hash1,hash2,p1=131,p2=13331,len; ll pow1[N],pow2[N]; map<ll,ll>mp; int mod=1000007; int main() { scanf("%s",s+1); len=strlen(s+1); long long ans=0; pow1[0]=1,pow2[0]=1; for (long long i=1;i<=len;i++) pow1[i]=pow1[i-1]*p1%mod,pow2[i]=pow2[i-1]*p2%mod; mp[0]=1; for (long long i=1;i<=len;i++) { if(!top||sta[top]!=s[i]) { sta[++top]=s[i]; hash1+=pow1[top]*(s[i]-'a'+1)%mod;hash1%=mod; hash2+=pow2[top]*(s[i]-'a'+1)%mod;hash2%=mod; } else { hash1+=mod-pow1[top]*(s[i]-'a'+1)%mod;hash1%=mod; hash2+=mod-pow2[top]*(s[i]-'a'+1)%mod;hash2%=mod; top--; } ans+=mp[hash1*mod+hash2]; mp[hash1*mod+hash2]++; } printf("%lld\n",ans); }