• CSP-S2019 D1T2 括号树


    CSP-S2019 D1T2 括号树

    洛谷传送门

    题目背景

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

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

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

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

    题目描述

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

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

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

    显然 s_is**i 是个括号串,但不一定是合法括号串,因此现在小 Q 想对所有的 ii(1leq ileq n1≤in)求出,s_is**i 中有多少个互不相同的子串合法括号串

    这个问题难倒了小 Q,他只好向你求助。设 s_is**i 共有 k_ik**i 个不同子串是合法括号串, 你只需要告诉小 Q 所有 i imes k_ii×k**i 的异或和,即:

    (1 imes k_1) ext{xor} (2 imes k_2) ext{xor} (3 imes k_3) ext{xor} cdots ext{xor} (n imes k_n)(1×k1) xor (2×k2) xor (3×k3) xor ⋯ xor (n×k**n)

    其中 xorxor 是位异或运算。

    输入格式

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

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

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

    输出格式

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


    题解:

    还是先放回忆杀。

    用了将近一个点来切T1,但是最后还是因为没开ull见了5分的祖宗。剩下的时间基本都在淦T2,因为T3基本上是毫无头绪。于是T2还是挂了。总之当时考场思路是一团乱麻,根本不知道自己想要写什么。还是蒟蒻太菜了。

    细细思考,题意需要我们干什么?首先,处理出从1号点到每个点的括号序列,然后统计它的合法子串数目,最后异或和。

    主要卡在如何统计合法子串数目(废话)。

    这种统计数目的题,肯定要先试一试递推。那么,递推的转移过程,其实就是看一个新的半括号进场的时候,对答案有什么样子的影响。可以发现的性质是,一个合法括号串一定是一个平衡括号串。如果是左括号,肯定还没构成合法括号串,如果是右括号,首先要看它平衡掉了哪个左括号。这样才能进一步确定这个平衡的区间到底是哪个。

    更进一步地,对于题目给出的合法括号串定义3,对于一个合法括号串的前面的所有合法括号串,皆可以与当前的括号串构成新的合法子串。这也是统计的时候唯一需要考虑加法原理的地方。

    所以可以得出一个状态转移的方程:设(cnt[i])表示以从根到(i)的合法串的数目(注意,并非合法子串)。(last[i])表示离i最近的未被匹配的左括号位置。

    即有:

    [cnt[i]=cnt[fa[last[i]]]+1 ]

    新匹配到的当然是一个新子串,其之前的合法串数目和它自己都会构成一个新的合法子串。于是更新cnt数组,同时,因为last已经被换掉了,所以也要更新last,其更新方法为:

    [last[i]=last[fa[last[i]]] ]

    比较好理解的。

    先放代码:

    #include<cstdio>
    #define ll long long
    using namespace std;
    const int maxn=5*1e5+10;
    int n;
    ll ans;
    char s[maxn];
    int tot,to[maxn],head[maxn],nxt[maxn],fa[maxn];
    ll cnt[maxn],last[maxn];
    //cnt[x]表示根节点到x点的合法串个数,last[x]表示距离x节点最近的未匹配左括号。
    void add(int x,int y)
    {
    	to[++tot]=y;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    void dfs(int x)
    {
    	last[x]=last[fa[x]];
    	if(s[x]=='(')
    		last[x]=x;
    	else if(last[x])
    		cnt[x]=cnt[fa[last[x]]]+1,last[x]=last[fa[last[x]]];
    	for(int i=head[x];i;i=nxt[i])
    		dfs(to[i]);
    }
    int main()  
    {
    	scanf("%d%s",&n,s+1);
    	for(int i=2;i<=n;i++)
    	{
    		int x;
    		scanf("%d",&x);
    		fa[i]=x;
    		add(x,i);
    	}
    	dfs(1);
    	ans=cnt[1];
    	for(int i=2;i<=n;i++)
    		cnt[i]+=cnt[fa[i]],ans^=(i*cnt[i]);
    	printf("%lld",ans);
    	return 0;
    }
    

    这个算法的精妙之处就在于:它的last数组采用了下传的形式,大大减少了时间复杂度。也就是在函数开始之前先把上面的信息复制下来,这样就免去了回溯的麻烦,以及,快速找到需要的信息。

    妙哉!

  • 相关阅读:
    Abp Zero 演示(链接)
    阿里中台战略是个伪命题(转)
    AlphaFlow智能BPM专家的博客
    绵绵用力方能久久为功 --《工程建设企业管理信息化实用案例精选》前言 -- 鲁贵卿
    业务梳理优化(政府、企业)---- 收集网上资料链接
    .NET for Apache® Spark™ 开源大数据分析工具
    Net Core 3.0 及 AspNet 3.0
    统一身份访问管理平台 (收集)-- Identity Access management platform
    SciSharp .Net 平台的人工智能,Net 如何调用 Python
    Identity Server4 及 其它 OpenId 服务器 学习
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13750383.html
Copyright © 2020-2023  润新知