草庐IT

蓝桥杯2022 括号序列树 第十三届蓝桥杯 决赛 C++ A组 J题

SpaceJellyfish 2023-03-28 原文

题面

有一棵二叉树,根结点上有一个空字符串,每个点的左儿子上的字符串为其父亲结点的字符串尾部额外加一个左括号,右儿子则是在尾部加一个右括号。树中的每个叶子结点上的字符串都分别和每个由 \(n\) 对括号组成的合法括号序列一一对应。
给定 \(n\),求此时这棵树的最大匹配所含的边数。(对 \(998244353\) 取模)

样例

输入:

9

输出:

10350

题解

题意就是说,一颗深度为 \(2n+1\) 的二叉树,从根节点开始向左子节点走相当于增加一个左括号,向右子节点走相当于增加一个右括号,先设这颗二叉树是满二叉树,然后不停地将所有不表示合法括号序列的叶子节点删掉,直到所有叶子节点都表示一个长度为 \(2n\) 的括号序列。

题目要求这棵树的最大匹配,那么我们不妨先构造一个最大匹配出来。这里实际上是贪心地去构造的。

不妨考虑一下这个非常简单的情况:

     1
    /
   2
  / \
 3   4
/\   /\
...  ...

第一个结论:在最大匹配中 \(2\) 一定参与匹配。因为如果 \(2\) 不参与匹配,那么最终 \(2\) 一定还能够和 \(1\) 匹配。

第二个结论:\(2\) 一定和 \(1\) 匹配。因为如果 \(2\)\(1\) 匹配,那么 \(3\)\(4\) 都可以继续去匹配;如果 \(2\)\(3\) 匹配,那么 \(1\) 无法再与 \(2\) 匹配,而 \(3\) 也无法再和其他点匹配了,这显然是不优的。

也就是说,对于一个度数为 \(1\) 的点我们一定会尽可能地让它匹配。于是我们可以考虑自下而上地去匹配,每匹配一个点就可以将该点删除,得到新的叶子节点,再从新的叶子节点去匹配。这样的话最终结论就是:答案等于奇数层的节点个数之和。

下一步是将节点合并。如图

          0
         /
        1
     /     \
    2       3
   /\      /
  4   5   6
  \  /\   /\
  8 9 10 11 12
  \ /\ /\ /\ /
... ... ... ...

将其合并为

         0
        /
       1
      / \
    2    3
   / \  /
  4   5/6
 / \ /  \
8 9/11 10/12
... ... ...

换句话说,我们构造一个 \(2n+1\)\(n+1\) 列的图,图中左儿子在父亲节点的左边一列,右儿子在父亲节点的右边一列,规定根节点在右上角,不能走出图外,且所有路径收敛到右下角。于是我们将走到了同一个位置的所有结点归为一类,该类节点的个数就是从根节点走到该节点的路径条数。

我们把节点标号改成该位置的节点个数,得到了

         1
        /
       1
      / \
     1   1
    / \ /
   1   2
  / \ / \
 1   3   2
... ... ...

显然这就是一个形状不太一样的杨辉三角了。假如你是个**数学天才**,或许你已经看出来了这是一个杨辉三角的差分。下面解释一下这个结论。

不妨补全这个杨辉三角,得到了

       1  -1
      / \ / \
     1   0  -1
    / \ / \ / \
   1   1  -1  -1
  / \ / \ / \ / \
 1   2   0  -2  -1
... ... ... ... ...

于是就可以看出来这是一个杨辉三角对位减去一个向右错位一格的杨辉三角。于是得到了公式

\(f(i,j)=C(i,j)-C(i,j-1)\)

由于我们要对奇数层求和,在图中也就是偶数行(因为这里首行从 \(0\) 开始了)那么对于前 \(n+1\) 行中的第 \(i\) 行(\(i\) 为偶数)就是求 \(\sum_{j=0}^{\frac i2} f(i,j)=C(i,\frac i2)\)

对于第 \(n+1\sim 2n\) 行则是上式减去一个前缀,所以最终的式子整理过后就是

\[f(n)=\sum_{i=0}^{n-1}C(2×i+1,i)-\sum_{i=\lceil\frac n2\rceil}^{n-1}C(2×i+1,2×i-n) \]

利用该公式计算答案即可获得满分了

代码

#include <cstdio>
using namespace std;
const int N = 5001, M = 2e6 + 1, p = 998244353;

int fpow(int base, int t = p - 2){
	int ret = 1;
	while(t){
		if(t & 1)
			ret = 1ll * ret * base % p;
		base = 1ll * base * base % p;
		t >>= 1;
	}
	return ret;
}

int n, fac[M] = {1}, facinv[M];

int C(int n, int m){
	return 1ll * fac[n] * facinv[m] % p * facinv[n - m] % p;
}

int main(){
	scanf("%d", &n);
	int ans = 0;
	for (int i = 1; i <= 2 * n; i++)
		fac[i] = 1ll * fac[i - 1] * i % p;
	facinv[2 * n] = fpow(fac[2 * n]);
	for (int i = 2 * n; i; i--)
		facinv[i - 1] = 1ll * facinv[i] * i % p;
	for (int i = 0; i < n; i++)
		ans = (ans + C(2 * i + 1, i)) % p;
	for (int i = (n - 1) / 2 + 1; i < n; i++)
		ans = (ans - C(2 * i + 1, 2 * i - n)) % p;
	printf("\n%d", (ans + p) % p);
	return 0;
}

有关蓝桥杯2022 括号序列树 第十三届蓝桥杯 决赛 C++ A组 J题的更多相关文章

  1. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  2. ruby - 带括号和 splat 运算符的并行赋值 - 2

    我明白了:x,(y,z)=1,*[2,3]x#=>1y#=>2z#=>nil我想知道为什么z的值为nil。 最佳答案 x,(y,z)=1,*[2,3]右侧的splat*是内联扩展的,所以它等同于:x,(y,z)=1,2,3左边带括号的列表被视为嵌套赋值,所以它等价于:x=1y,z=23被丢弃,而z被分配给nil。 关于ruby-带括号和splat运算符的并行赋值,我们在StackOverflow上找到一个类似的问题: https://stackoverflow

  3. ruby - 在 Ruby 中比较序列 - 2

    假设我必须(小型到中型)阵列:tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]如何确定tokens是否以相同的顺序包含template的所有条目?(请注意,在上面的示例中,应忽略第一个“ccc”,从而由于最后一个“ccc”而导致匹配。) 最佳答案 这适用于您的示例数据。tokens=["aaa","ccc","xxx","bbb","ccc","yyy","zzz"]template=["aaa","bbb","ccc"]po

  4. Ruby 正则表达式匹配逗号,但忽略括号中的逗号 - 2

    我正在尝试通过正则表达式拆分参数列表。这是一个带有我的参数列表的字符串:"a=b,c=3,d=[1,3,5,7],e,f=g"我想要的是:["a=b","c=3","d=[1,3,5,7]","e","f=g"]我试过先行,但Ruby不允许使用动态范围后行,所以这行不通:/(?如何让正则表达式忽略方括号中的所有内容? 最佳答案 也许这样的东西对你有用:str.scan(/(?:\[.*?\]|[^,])+/)编辑再三考虑。简单的非贪婪匹配器在某些嵌套括号的情况下会失败。 关于Ruby正则

  5. ruby - 如何在ruby中提取方括号内的内容 - 2

    我正在尝试提取方括号内的内容。到目前为止,我一直在使用它,它有效,但我想知道我是否可以直接在正则表达式中使用某些东西,而不是使用这个删除功能。a="Thisissuchagreatday[coolawesome]"a[/\[.*?\]/].delete('[]')#=>"coolawesome" 最佳答案 差不多。a="Thisissuchagreatday[coolawesome]"a[/\[(.*?)\]/,1]#=>"coolawesome"a[/(?"coolawesome"第一个依赖于提取组而不是完全匹配;第二个利用前瞻和

  6. ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader - 2

    首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟

  7. 映宇宙2022年营收63亿元:同比下降三成,毛利率提升4.3个百分点 - 2

    3月26日,映宇宙(HK:03700,即“映客”)发布截至2022年12月31日的2022年度业绩财务报告。财报显示,映宇宙2022年的总营收为63.19亿元,较2021年同期的91.76亿元下降31.1%。2022年,映宇宙的经营亏损为4698.7万元,2021年同期则为净利润4.57亿元;期内亏损(净亏损)为1.68亿元,2021年同期的净利润为4.33亿元;非国际财务报告准则经调整净利润为3.88亿元,2021年同期为4.82亿元,同比下降19.6%。 映宇宙在财报中表示,收入减少主要是由于行业竞争加剧,该集团对旗下产品采取更为谨慎的运营策略以应对市场变化。不过,映宇宙的毛利率则有所提升

  8. 机器学习——时间序列ARIMA模型(四):自相关函数ACF和偏自相关函数PACF用于判断ARIMA模型中p、q参数取值 - 2

    文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk​=Var(yt​)Cov(yt​,yt−k​)​其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞

  9. 蓝桥杯备赛(二) - 2

    目录前言: 一、ASC分析代码实现二、 卡片分析代码实现三、 直线分析代码实现四、货物摆放分析代码实现小结:前言:  在刷题的过程中,发现蓝桥杯的题目和力扣的差别很大。让人有一种不一样的感觉,蓝桥杯题目偏向对于实际问题用编程去的解决,而力扣给人感觉很锻炼自己的编程思维,逻辑能力。两者结合去刷,相信会有不一样的收获。 一、ASC  已知大写字母A的ASCII码为65,请问大写字母L的ASCII码是多少?分析  这道题目看上去很简单,我们需确定自己计算的准确,所以我建议用编程去解决。代码实现publicclassTest8{publicstaticvoidmain(String[]args){Sy

  10. ruby-on-rails - Rails 编辑序列化的 JSON 数据 - 2

    我有一个存储JSON数据的列。当它处于编辑状态时,我不知道如何显示它。serialize:value,JSON=f.fields_for:valuedo|ff|.form-group=ff.label:short=ff.text_field:short,class:'form-control'.form-group=ff.label:long=ff.text_field:long,class:'form-control' 最佳答案 代替=f.fields_for:valuedo|ff|请使用以下代码:=f.fields_for:va

随机推荐