CSP-S2019提高组day1-T2:括号树

news2024/9/28 15:22:15

题目链接

[CSP-S2019] 括号树

题目描述

本题中合法括号串的定义如下:

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

本题中子串不同的子串的定义如下:

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

一个大小为 n n n 的树包含 n n n 个结点和 n − 1 n - 1 n1 条边,每条边连接两个结点,且任意两个结点间有且仅有一条简单路径互相可达。

小 Q 是一个充满好奇心的小朋友,有一天他在上学的路上碰见了一个大小为 n n n 的树,树上结点从 1 ∼ n 1 \sim n 1n 编号, 1 1 1 号结点为树的根。除 1 1 1 号结点外,每个结点有一个父亲结点, u u u 2 ≤ u ≤ n 2 \leq u \leq n 2un)号结点的父亲为 f u f_u fu 1 ≤ f u < u 1 ≤ f_u < u 1fu<u)号结点。

小 Q 发现这个树的每个结点上恰有一个括号,可能是()。小 Q 定义 s i s_i si 为:将根结点到 i i i 号结点的简单路径上的括号,按结点经过顺序依次排列组成的字符串。

显然 s i s_i si 是个括号串,但不一定是合法括号串,因此现在小 Q 想对所有的 i i i 1 ≤ i ≤ n 1\leq i\leq n 1in)求出, s i s_i si 中有多少个互不相同的子串合法括号串

这个问题难倒了小 Q,他只好向你求助。设 s i s_i si 共有 k i k_i ki 个不同子串是合法括号串, 你只需要告诉小 Q 所有 i × k i i \times k_i i×ki 的异或和,即:
( 1 × k 1 )  xor  ( 2 × k 2 )  xor  ( 3 × k 3 )  xor  ⋯  xor  ( n × k n ) (1 \times k_1)\ \text{xor}\ (2 \times k_2)\ \text{xor}\ (3 \times k_3)\ \text{xor}\ \cdots\ \text{xor}\ (n \times k_n) (1×k1) xor (2×k2) xor (3×k3) xor  xor (n×kn)
其中 x o r xor xor 是位异或运算。

输入格式

第一行一个整数 n n n,表示树的大小。

第二行一个长为 n n n 的由() 组成的括号串,第 i i i 个括号表示 i i i 号结点上的括号。

第三行包含 n − 1 n − 1 n1 个整数,第 i i i 1 ≤ i < n 1 \leq i \lt n 1i<n)个整数表示 i + 1 i + 1 i+1 号结点的父亲编号 f i + 1 f_{i+1} fi+1

输出格式

仅一行一个整数表示答案。

样例 #1

样例输入 #1

5
(()()
1 1 2 2

样例输出 #1

6

提示

【样例解释1】

树的形态如下图:
在这里插入图片描述

将根到 1 号结点的简单路径上的括号,按经过顺序排列所组成的字符串为 (,子串是合法括号串的个数为 0 0 0

将根到 2 号结点的字符串为 ((,子串是合法括号串的个数为 0 0 0

将根到 3 号结点的字符串为 (),子串是合法括号串的个数为 1 1 1

将根到 4 号结点的字符串为 (((,子串是合法括号串的个数为 0 0 0

将根到 5 号结点的字符串为 ((),子串是合法括号串的个数为 1 1 1

【数据范围】

在这里插入图片描述

算法思想

根据题目描述,要求的是树中从根结点到 i i i 号结点组成的括号串 s i s_i si中,合法括号串的个数。示例参考提示【样例解释1】。

对于任意括号串 s i s_i si如下图所示:
在这里插入图片描述
要计算括号串 s i s_i si中合法括号串的个数,不妨设为 f ( i ) f(i) f(i),从最后一步分析,也就是根据 i i i号结点的选择分成两种情况:

  • 不选择 i i i号结点,那么方案数等于括号串 s i − 1 s_{i-1} si1中合法括号串的个数,即 f ( i − 1 ) f(i-1) f(i1)
  • 选择 i i i号结点(前提是 i i i号结点是)),那么 i i i结尾的合法括号串的个数如何计算呢,不妨设其为 g ( i ) g(i) g(i)
    • 首先找到与 i i i号结点匹配的(的位置,不妨设为 j j j(如上图所示),那么从 j j j i i i就是一组合法的括号串
    • 其次考虑 j j j之前合法括号串的个数,即以 j − 1 j-1 j1结尾的合法括号串的个数,就是 g [ j − 1 ] g[j-1] g[j1]
    • 可得以 i i i结尾的合法括号串的个数,就是在以 j − 1 j-1 j1结尾的合法括号串后添加了 1 1 1组,即 g [ i ] = g [ j − 1 ] + 1 g[i]=g[j-1]+1 g[i]=g[j1]+1

那么, f ( i ) = f ( i − 1 ) + g [ i ] f(i)=f(i-1)+g[i] f(i)=f(i1)+g[i],其中 g [ i ] g[i] g[i]表示 i i i结尾的合法括号串的个数 g [ i ] = g [ j − 1 ] + 1 g[i]=g[j-1]+1 g[i]=g[j1]+1 j j j是与 i i i匹配的左括号(的位置。

进一步分析, j − 1 j-1 j1结尾的合法括号串的个数 g [ j − 1 ] g[j-1] g[j1],其实就是从根节点到 j − 1 j-1 j1号结点的所有合法括号串中去掉不选择 j − 1 j-1 j1号结点的方案数,即 g ( j − 1 ) = f ( j − 1 ) − f ( j − 2 ) g(j-1)=f(j-1)-f(j-2) g(j1)=f(j1)f(j2)

综上所述, f ( i ) = f ( i − 1 ) + f ( j − 1 ) − f ( j − 2 ) + 1 f(i)=f(i-1)+f(j-1)-f(j-2)+1 f(i)=f(i1)+f(j1)f(j2)+1,其中 j j j是与 i i i匹配的左括号(的位置。

通过上面的分析,要想进行计算还要解决两个问题:

  • 在树上如何得到括号串 i i i位置的上一个结点 i − 1 i-1 i1

在树上 i i i位置的上一个结点,就是 i i i的父节点,可以设置一个数组p[i]来存储i的父节点

  • 如何得到与 i i i匹配的左括号(的位置 j j j

括号匹配,可以通过栈来实现。如果i位置是左括号,直接入栈,如果i位置是右括号,则栈顶就是与之匹配的左括号的位置。

下面从动态规划的角度将上述分析整理一下。

状态表示

  • f [ i ] f[i] f[i]表示树中从根结点到 i i i 号结点组成的括号串 s i s_i si中合法括号串的个数

最终答案 = ( 1 × f [ 1 ] )  xor  ( 2 × f [ 2 ] )  xor  ( 3 × f [ 3 ] )  xor  ⋯  xor  ( n × f [ n ] ) = (1 \times f[1])\ \text{xor}\ (2 \times f[2])\ \text{xor}\ (3 \times f[3])\ \text{xor}\ \cdots\ \text{xor}\ (n \times f[n]) =(1×f[1]) xor (2×f[2]) xor (3×f[3]) xor  xor (n×f[n])。注意 n n n的范围很大( n ≤ 5 × 1 0 5 n\le5\times10^5 n5×105),会爆int

状态计算

从最后一步分析,根据 i i i号结点的选择分成两种情况:

  • 不选择 i i i号结点,那么方案数等于括号串 s i − 1 s_{i-1} si1中合法括号串的个数,即 f [ p [ i ] ] f[p[i]] f[p[i]],其中 p [ i ] p[i] p[i]表示 i i i的父结点,也就是括号串中 i i i之前的结点
  • 选择 i i i号结点(前提是 i i i号结点是)),先找到与 i i i匹配的左括号的位置 j j j,其父节点为 p [ j ] p[j] p[j],那么以 i i i结尾的合法括号串的个数 f [ p [ j ] ] − f [ p [ p [ j ] ] ] + 1 f[p[j]]-f[p[p[j]]]+1 f[p[j]]f[p[p[j]]]+1

那么, f [ i ] = f [ p [ i ] ] + f [ p [ j ] ] − f [ p [ p [ j ] ] ] + 1 f[i]=f[p[i]]+f[p[j]]-f[p[p[j]]]+1 f[i]=f[p[i]]+f[p[j]]f[p[p[j]]]+1

初始状态

根节点编号为 1 1 1,根结点自己组成的合法括号串的个数为 0 0 0,即 f [ 1 ] = 0 f[1]=0 f[1]=0

时间复杂度

  • 状态数为 n n n
  • 每个结点的状态只会计算一次,时间复杂度 O ( 1 ) O(1) O(1)

总的时间复杂度为 O ( n ) O(n) O(n)

代码实现

#include <iostream>
#include <vector>
using namespace std;
const int N = 5e5 + 10;
typedef long long LL;
char s[N];
int p[N], stk[N], top;
//f[i]表示树中从根结点到i号结点组成的括号串中合法的方案数
LL f[N]; 
vector<int> g[N]; //邻接表
void dfs(int i)
{
    if(s[i] == '(')
    {
        stk[++ top] = i; //左括号入栈
        f[i] = f[p[i]]; //不选择i号结点
        for(int k : g[i]) 
            dfs(k); //递归处理子结点
        top --; //回溯,恢复现场
    }
    else //右括号
    {
        if(top == 0) //栈空,没有与之匹配的左括号
        {
            f[i] = f[p[i]]; //不选择i号结点
            for(int k : g[i]) 
                dfs(k); //递归处理子结点
        }
        else
        {
            int j = stk[top --]; //从栈顶取出与i匹配的右括号位置
            f[i] = f[p[i]] + f[p[j]] - f[p[p[j]]] + 1; //状态计算
            for(int k : g[i]) 
                dfs(k); //递归处理子结点
            stk[++ top] = j; //回溯,恢复现场
        }
    }
}
int main()
{
    int n;
    scanf("%d%s", &n, s + 1);
    for(int i = 2; i <= n; i ++)
    {
        scanf("%d", &p[i]); //输入i的父结点
        g[p[i]].push_back(i); //将i添加到a的子结点中
    }
    
    dfs(1);
    
    LL ans = 0;
    for(int i = 1; i <= n; i ++) ans ^= i * f[i];
    printf("%lld\n", ans);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1323432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vscode颜色主题插件one dark Pro安装

1.点击扩展图标→搜索“one dark Pro”→第一个点击安装 2.安装成功后&#xff0c;不要忘了点击设置颜色主题 3.看下效果&#xff1a;

【日积月累】sql执行语句优化

目录 sql执行语句优化 1.前言2.sql执行语句优化2.1语句注意类1.避免使用 * 查询(全表查询)2.限制查询返回数3.小数据集驱动大数据集4.group by 优化5.尽量使用数值替代字符串类型6.使用varchar代替char7.批量插入性能提升 3.误操作导致索引失效1.避免查询条件字符串没有加2.避…

JVS低代码和智能BI(自助式数据分析)12.19更新功能说明

低代码更新功能 新增: 1、表单组件&#xff1a;标题、分割线、按钮等非数据组件增加小程序端隐藏设置&#xff1b; 隐藏设置允许开发者对表单组件中的非数据组件进行隐藏&#xff0c;例如&#xff0c;可能只想展示表单的部分内容&#xff0c;或者希望在特定条件下显示或隐藏…

HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】

一.HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】 1.1 项目背景 HarmonyOS(鸿蒙操作系统)是华为公司推出的一种分布式操作系统。它被设计为一种全场景、全连接的操作系统,旨在实现在各种设备之间的无缝协同和共享,包括智能手机、平板电脑、智能…

HamronyOS 自动化测试框架使用指南

概述 为支撑 HarmonyOS 操作系统的自动化测试活动开展&#xff0c;我们提供了支持 JS/TS 语言的单元及 UI 测试框架&#xff0c;支持开发者针对应用接口进行单元测试&#xff0c;并且可基于 UI 操作进行 UI 自动化脚本的编写。 本指南重点介绍自动化测试框架的主要功能&#x…

grafana基本使用

一、安装grafana 1.下载 官网下载地址&#xff1a; https://grafana.com/grafana/download官网包的下载地址&#xff1a; yum install -y https://dl.grafana.com/enterprise/release/grafana-enterprise-10.2.2-1.x86_64.rpm官网下载速度非常慢&#xff0c;这里选择清华大…

【单调栈】LeetCode1776:车队

作者推荐 【贪心算法】【中位贪心】.执行操作使频率分数最大 涉及知识点 单调栈 题目 在一条单车道上有 n 辆车&#xff0c;它们朝着同样的方向行驶。给你一个长度为 n 的数组 cars &#xff0c;其中 cars[i] [positioni, speedi] &#xff0c;它表示&#xff1a; positi…

markdown文档主题颜色修改

目录 1、选择任意想选择的markdown文档主题css文件&#xff1a; 2、修改背景颜色 1、选择任意想选择的markdown文档主题css文件&#xff1a; 使用工具Typora文件主题路径&#xff1a; C:\Users\AppData\Roaming\Typora\themes&#xff0c;此处我这边就是copy了xydark的css文…

【LeetCode刷题笔记(8-2)】【Python】【接雨水】【单调栈】【困难】

文章目录 引言接雨水题目描述提示 解决方案2&#xff1a;【单调栈】结束语 【接雨水】 【LeetCode刷题笔记&#xff08;8-1&#xff09;】【Python】【接雨水】【动态规划】【困难】 引言 编写通过所有测试案例的代码并不简单&#xff0c;通常需要深思熟虑和理性分析。虽然这…

总线地址/物理地址/虚拟地址

参考&#xff1a; 总线地址、物理地址、虚拟地址-CSDN博客 内存管理&#xff1a;物理地址、虚拟地址、逻辑地址_虚拟地址和物理地址-CSDN博客 总线地址 总线地址和地址总线是一个概念。地址总线 (Address Bus&#xff1b;又称&#xff1a;位址总线) 属于一种电脑总线 &#xf…

React和umi搭建项目的操作步骤

​​​​​​一、react脚手架新建项目 (1.1)、命令行 前提&#xff1a;react ES2015,nodejs v8 npx create-react-app myReactName //2022年v16以下版本 myReactName(自定义项目名) react中文官网&#xff0c;快速上手&#xff1a;react中文官网 react框架&#xff0c;…

Linux系统中查看路由表的命令(ip route)

以下命令是在Linux系统中查看路由表的命令&#xff1a; 在Linux系统中&#xff0c;有多种方法可以查看路由设置。以下是一些常用的命令&#xff1a; ip route 或 ip -4 route&#xff08;IPv4&#xff09;/ ip -6 route&#xff08;IPv6&#xff09;&#xff1a; 这是最常用且功…

算法设计与分析期末知识点总结

一、概论 1、算法设计的目标&#xff1a; &#xff08;1&#xff09;正确性 &#xff08;2&#xff09;可使用性&#xff08;用户友好性&#xff09; &#xff08;3&#xff09;可读性 &#xff08;4&#xff09;健壮性 &#xff08;5&#xff09;高效率与低存储量需求 算…

vue 快速入门+vite前端构建工具

四、Vue3简介和快速体验 4.1 Vue3介绍 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c;帮助你高效地开发用户界面。无论是简…

迪文屏开发保姆级教程——页面键盘

迪文屏页面键盘保姆级教程。 本篇文章主要介绍了在DGBUS平台上使用页面键盘的步骤。 文章目录 一、前言 开发环境 二、使用步骤 1.准备素材 2.打开DGUS工程&#xff0c;导入素材。 3.生成ICL文件。 4.添加数据变量显示控件 5.添加数据录入控件 A.变量地址设置 B.变量类…

外媒发稿最好的宣传方法是什么?大舍传媒

外媒发稿最好的宣传方法是什么&#xff1f; 引言 在如今信息爆炸的时代&#xff0c;外媒发稿的宣传方法至关重要。大舍传媒作为一家业内知名的传媒公司&#xff0c;积累了丰富的经验和成功案例。本文将探讨外媒发稿最好的宣传方法&#xff0c;旨在帮助读者更好地推广自己的信…

将输入的文本包装成多个行使每行的字符数不超过指定的列宽textwrap.fill()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将输入的文本包装成多个行 使每行的字符数不超过指定的列宽 textwrap.fill() [太阳]选择题 请问以下代码每行最多能输出字符数是&#xff1f; import textwrap text "This is a long …

(PC+WAP)装修设计公司网站模板 家装公司网站源码下载

(PCWAP)装修设计公司网站模板 家装公司网站源码下载 PbootCMS内核开发的网站模板&#xff0c;该模板适用于装修设计、家装公司类等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b; PCWAP&#xff0c;同一个后台&#xff0c…

【Redis】四、Redis.conf详解

文章目录 Redis.conf详解单位网络通用 GENERAL快照REPLICATION 复制SECURITY 安全限制 CLIENTSAPPEND ONLY 模式 aof配置 Redis.conf详解 启动的时候&#xff0c;就通过配置文件来启动&#xff01; 工作中&#xff0c;一些小小的配置&#xff0c;可以让你脱颖而出&#xff01;…

多域名证书和通配符证书的区别?

先来说说多域名证书&#xff08;别急&#xff0c;通配符证书&#xff0c;马上就有戏&#xff09;。多域名证书&#xff0c;正式的名字叫主题备用名称&#xff08;SAN&#xff09;证书。想象一下&#xff0c;它们就像是一个超级英雄联盟&#xff0c;能在一个SSl证书下保护包含不…