括号序列
括号序列
题目描述
可怜不喜欢括号序列,但是她发现总是有人喜欢出括号序列的题。
为了让全世界都能感受到她的痛苦,她想要写一个转换器:它能把普通的小写字符串转换成长度相同的合法的括号序列。
在可怜的构思中,这样的转换器需要满足如下两个条件:
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;
}