关于求合法括号子序列个数

求合法括号子序列个数

发了近半天时间都没人发现里面的致命错误() 还好我悄咪咪改了

题意

背景

合法括号串的定义如下:

  1. () 是合法括号串。
  2. 如果 A 是合法括号串,则 (A) 是合法括号串。
  3. 如果 AB 是合法括号串,则 AB 是合法括号串。

子串不同的子串的定义如下:

  1. 字符串 S 的子串是 S连续的任意个字符组成的字符串。S 的子串可用起始位置 l 与终止位置 r 来表示,记为 S(l,r)1lr|S||S| 表示 S 的长度)。
  2. S 的两个子串视作不同当且仅当它们在 S 中的位置不同,即 l 不同或 r 不同。

题目

给出一个括号串 s(其不一定是合法括号串),问 s 中有多少个互不相同的子串合法括号串

样例

样例输入

(()()

样例输出

3

分析

观察序列1:

()()()

pos=2 的时候,对答案的贡献值为 1

pos=4 的时候,本身 [3,4] 就有一个满足要求的括号序列,再合并上前面的成为 [1,4] ,于是对答案的贡献值就为 2 ,再加上前面 [1,2] 本身有的括号序列,总共为 3

pos=6 时,总共的贡献值为 3 ,加上前面的有 3+3=6 种。其他位置均没有贡献(左括号没有贡献值)。

总之,pos16 时对答案的贡献分别为 0,1,0,2,0,3 ,合并后的总答案为 0,1,1,3,3,6


观察序列2:

())()

pos=2 时,对答案贡献为 1

pos=3 时,由于不满足成匹配的括号序列,所以没有贡献(我们只看右括号的贡献值)。

pos=5 时,由于 pos=3 时多了一个后括号,所以 [1,3] 不匹配,导致 [1,5] 成不了一个匹配的括号序列,所以对答案的贡献仍为 1

pos15 时对答案的贡献分别为 0,1,0,0,1 ,合并后的总答案为 0,1,1,1,2


观察序列3:

()(())

pos=2 时,贡献为 1

pos=5 时,由于 pos=3 是在中间断开,所以 [1,5] 不能匹配,所以贡献仍为 1

pos=6 时,我们发现 [1,2] 是匹配的。故 [1,2],[3,6] 能合成一个匹配的序列,所以对答案贡献为 2

pos16 时对答案的贡献分别为 0,1,0,0,1,2 ,合并后的总答案为 0,1,1,1,2,4


可以发现,一个后括号如果能匹配一个前括号,假设这个前括号的前1位同样有一个已经匹配了的后括号,那么我们就可以把当前的匹配括号序列和之前的匹配括号序列合并。当前的这个后括号的贡献值,其实就等于前面那个后括号的贡献值 + 1。

Elaina's Code

int sum=0,tot[N];
string s;
stack<int> sta;
signed main(){
	cin>>s;
	for(int i=0;i<s.size();i++){
		if(s[i]=='(') sta.push(i);
		if(s[i]==')'){
			if(!sta.empty()){
				int l=sta.top();
				sta.pop();
				tot[i]=tot[l-1]+1;
			}
		}
		sum+=tot[i];
	}
	cout<<sum;
	return Elaina;
}
posted @   Elaina_0  阅读(118)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示