P5658 CSP-S2019括号树
[CSP-S2019] 括号树 (傻逼绿题
题目背景
本题中合法括号串的定义如下:
()
是合法括号串。- 如果
A
是合法括号串,则(A)
是合法括号串。 - 如果
A
,B
是合法括号串,则AB
是合法括号串。
本题中子串与不同的子串的定义如下:
- 字符串
S
的子串是S
中连续的任意个字符组成的字符串。S
的子串可用起始位置 与终止位置 来表示,记为 ( , 表示 S 的长度)。 S
的两个子串视作不同当且仅当它们在S
中的位置不同,即 不同或 不同。
题目描述
一个大小为
小 Q 是一个充满好奇心的小朋友,有一天他在上学的路上碰见了一个大小为
小 Q 发现这个树的每个结点上恰有一个括号,可能是(
或)
。小 Q 定义
显然
这个问题难倒了小 Q,他只好向你求助。设
其中
输入格式
第一行一个整数
第二行一个长为 (
与)
组成的括号串,第
第三行包含
输出格式
仅一行一个整数表示答案。
样例 #1
样例输入 #1
5 (()() 1 1 2 2
样例输出 #1
6
提示
【样例解释1】
树的形态如下图:
将根到 1 号结点的简单路径上的括号,按经过顺序排列所组成的字符串为 (
,子串是合法括号串的个数为
将根到 2 号结点的字符串为 ((
,子串是合法括号串的个数为
将根到 3 号结点的字符串为 ()
,子串是合法括号串的个数为
将根到 4 号结点的字符串为 (((
,子串是合法括号串的个数为
将根到 5 号结点的字符串为 (()
,子串是合法括号串的个数为
【数据范围】
思路
很容易想到,如果给出的字符串刚好是一条链,那么刚好就是一个线性dp,由于要计算每一个i结尾的字符串中答案数,所以定义
先从一组手搓数据出发(假设这是一条链的情况):
相对应的答案是:
我们以第六个节点为例子,首先显而易见的:第二个节点的
与这个后括号单独匹配的前括号(记其位置为
任意的
需要维护的数据:
维护方式:
在把所有定义为
点击查看代码
void dfs(int x,int las) { if(a[x]=='(') { if(a[fa[x]]==')'&&las==fa[x])pre[x]=fa[x]; s[++top]=x; } else { if(top==0)ans[x]=0; else { ans[x]=ans[pre[s[top]]]+1; top--; } } sum[x]=sum[fa[x]]+ans[x]; // printf("ans:[%d]:%d\n",x,ans[x]); for(int i=head[x];i;i=E[i].nex)dfs(E[i].v,(a[x]=='('?las:x)); }
这样的弊端在于什么呢:通过全局变量的
点击查看代码
void dfs(int x,int las) { int mem=s[top]; if(a[x]=='(') { if(a[fa[x]]==')'&&las==fa[x])pre[x]=fa[x]; s[++top]=x; } else { if(top==0)ans[x]=0; else { ans[x]=ans[pre[s[top]]]+1; // for(int i=1;i<=top;i++)printf("%c",a[s[top]]); top--; } } sum[x]=sum[fa[x]]+ans[x]; // printf("ans[%d]:%d sum[%d]:%d\n",x,ans[x],x,sum[x]); for(int i=head[x];i;i=E[i].nex) dfs(E[i].v,(a[x]=='('?las:x)); if(a[x]=='(')s[--top]=mem; else s[++top]=mem; }
然而这样交上去依然只有
点击查看代码
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/16709786.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!