括号序列

括号序列

题目描述

 

可怜不喜欢括号序列,但是她发现总是有人喜欢出括号序列的题。

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

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

  1.结果的括号序列必须要是合法的,即左右括号必须要是相匹配的。

  2.对于一堆相匹配的左右括号,他们所在的位置原来的小写字母必须相同。

举例来说,对于字符串aabaab,()(())就是一个合法的答案,而()()()不满足第二个条件,  (((())不满足第一个条件。

可怜发现对于一个小写字符串,有时候有很多满足条件的括号序列,有些时候一个都没有。

于是可怜给出了一个小写字符串,她想让你帮她算一下,有多少个不同的子串满足能转换成合法的括号序列。

 

输入

 

输入一行一个小写字符串s。

 

输出

 

输出一行一个整数,表示答案。


solution

首先我们考虑暴力每一个起点,用栈维护。当栈为空时,满足j~i为合法的位置。

效率O(n^2)

那么显然是T了,我们考虑从头开始只维护一个栈,记录下每一个位置的栈的状态。

状态用hash值表示

显然相同状态的栈可以互相贡献,那我们排序一下,统计就行。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll unsigned long long
#define p 998244353
#define maxn 1000006
using namespace std;
int n,id[maxn],top;
char ch[maxn],zh[maxn];
ll s[maxn];
int main()
{
    scanf("%s",ch+1);
    s[0]=0;n=strlen(ch+1);
    for(int i=1;i<=n;i++){
        if(top>0&&ch[i]==zh[top]){
            s[i]=s[id[top]];top--;
        }
        else {
            zh[++top]=ch[i];id[top]=i-1;
            s[i]=s[i-1]*p+ch[i];
        }
    }
    //for(int i=0;i<=n;i++)cout<<s[i]<<endl;
    sort(s,s+n+1);
    int i=0;
    long long ans=0;
    while(i<=n){
        int j=i;while(s[j]==s[i]&&j<=n)j++;
        int l=j-i;
        ans=ans+(1LL)*l*(l-1)/2;
        i=j;
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/liankewei/p/10358767.html