【AUOJ1588】括号序列

题面

温神不喜欢括号序列,但是他发现总是有人喜欢出括号序列的题。

为了让全世界都能感受到他的痛苦,他想要写一个转换器:它能把普通的小写字符串转换成长度相同的合法的括号序列。

在温神的构思中,这样的转换器需要满足如下两个条件:

  1. 结果的括号序列必须要是合法的,即左右括号必须要是相匹配的。
  2. 对于一对相匹配的左右括号,他们所在的位置原来的小写字母必须相同。

举例来说,对于字符串 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);
}
     

猜你喜欢

转载自www.cnblogs.com/NSD-email0820/p/9823488.html