2023.3.3 题解
G - Rook Path
题意
有一个 \(n \times m\) 的矩阵,一开始有个物品放在 \((x_1, y_1)\) 上。
有 \(k\) 次操作,每次操作可以将这个物品移动到同一行或者同一列的另一个格子上。
请你求出在 \(k\) 次操作后,使得这个物品到达 \((x_2, y_2)\) 的方法有多少种,对 998244353
取模。
思路
首先,这道题我们先考虑暴力。
\(dp_{x, y, k}\) 表示走 \(k\) 步到格子 \((x, y)\) 的方案数。
那么就有转移:
所以,状态总数为 \(n \times m \times k\),每次有 \(n + m\) 种转移,总时间复杂度为 \(O(n \times m \times k \times (n + m))\),也就是 \(10 ^ {33}\),很明显会超时。
通过打表输出 dp
数组,我们可以发现,整个矩阵最后的结果一共可以分为四种:
-
起点
-
和起点同行的点
-
和起点同列的点
-
和起点不同行也不同列的点
所以,\(dp_{k, 0}\) 表示用 \(k\) 步走到起点的方案数,\(dp_{k, 1}\) 表示用 \(k\) 步走到与起点同行的其他的点的方案数,\(dp_{k, 2}\) 表示用 \(k\) 步走到与起点同列的其他的点的方案数,\(dp_{k, 3}\) 表述用 \(k\) 步走到和起点不同行也不同列的点的方案数。
那么,转移是什么呢?
我们可以画一个图来看一看。
所以,时间复杂度为 \(O(k)\)。
H - 对称二叉树
题意
如果一颗有点权的树满足以下条件,那么它就是一颗对称二叉树:
-
二叉树
-
将这棵树所有节点的左右子树交换,新树和原树对应位置的结构相同且点权相等
现在给出一棵二叉树和每个点的点权 \(v_i\),希望你找出它的一棵子树,该子树为对称二叉树,且节点数最多。请输出这棵子树的节点数。
注意:只有树根的树也是对称二叉树。
思路
首先,我们先想一想,要怎么判断一棵树是否为对称二叉树。
很明显,这个题目的判断部分是一个分治结构。
Check(i, j)
表示判断以 i
为根的子树是否与以 j
为根的子树的结构以及点权是否相等。
所以 Check(i, j) = Check(l[i], r[j]) && Check(r[i], l[j])
然后直接一边 dfs
,一边 Check
就可以了。
I - 加分二叉树
题意
对于一颗树上的任意一颗子树来说,它的加分是 它的左子树的加分 \(\times\) 它的右子树的加分 + 它的分数。
如果子树为空,加分为 1。
试求一棵符合中序遍历为 \((1,2,3,\ldots,n)\) 且加分最高的二叉树 \(\text{tree}\)。要求输出
-
\(\text{tree}\) 的最高加分。
-
\(\text{tree}\) 的前序遍历。
思路
首先,因为题目规定了中序遍历,而中序遍历的遍历方式是 左根右,所以可以看出,这是一个分治结构:
F(l, r) 表示中序遍历为 l ... r 的子树的最大加分
所以就有转移 F(l, r) = max(F(l, i - 1) + a[i] + F(i + 1, r))
,其中 i
为当前这个子树的根。
也就是枚举每一个根,取所有取值的最大值,再计算答案。
但是,应该怎么输出前序遍历呢?
很简单,因为前序遍历的遍历方式是 根左右,所以可以用 root[l][r]
表示 l ... r
的子树的根,再做一次递归即可。