「CSP-J」做题记录

「CSP-J」做题记录

记号:

  • A:自己做出来的。
  • B:看题解提示做出来的。
  • C:对着题解做出来的。

  1. [CSP-J2019 江西] 道路拆除 (A)

    我们可以把问题转化一下:求出最少要留下多少边,使得从首都出发,能到达 \(s_1\) 号与 \(s_2\)号城市,且所要花费的最短时间分别不超过 \(t_1\)\(t_2\)。最终答案就是 \(m\) 减去最少剩下的边数。

    \(s_1 = s_2\) 时是好做的:跑一遍最短路即可。

    \(s_1 \not= s_2\) 时,\(1 \mapsto s_1\)\(1 \mapsto s_2\) 两条最短路最开始是重合的(至少共有 \(1\) 这个节点)。我们假设在某个点 \(u\) 以后,两条路径没有公共边。那么我们可以枚举所有的点作为 \(u\),用 \(\operatorname{dis}(1 \mapsto u) + \operatorname{dis}(u \mapsto s_1) + \operatorname{dis}(u \mapsto s_2)\) 来更新最少剩余边数。那如果在两条路径分开之后,在某个地方又重合了呢?容易证明,在我们枚举点的过程中,一定可以找到一个更优的点来替换掉这种情况(此处有张图会更好理解,但我懒得画了),所以这种方法是正确的。

  2. [CSP-J2019 江西] 次大值 (A+B)

    自己写对了,但一些结论看了题解才完全想清楚。

    首先排序+去重,设排序后的数组为 \(b\)

    运用取模的两个关键的不等式:\(a \bmod b < b\)\(a \bmod b \le a\),当且仅当 \(a < b\) 时等号成立。换句话说,如果 \(a < b\),取模的结果比二者都小。

    把除了 \(b_{n-1}\) 以外的数模上它可以得到它本身,所以最大值一定是 \(b_{n-1}\),而次大值不小于 \(b_{n-2}\)。另一方面,\(b_{n} \bmod b_{n-1}\) 可能大于 \(b_{n-2}\),但其它任意两个数取模一定小于 \(b_{n-2}\) (根据上文的不等式)。所以比较这两种情况即可。

  3. [CSP-J2019 江西] 非回文串 (A)

    正难则反,考虑计算回文串的个数,用 \(n!\) 减去回文串的个数即为答案。

    \(\operatorname{cnt}(c)\) 表示原串中字符 \(c\) 的个数。显然,若超过一个字符出现的个数为奇数,那么不可能组成回文串。下面假设所有字符出现的个数均为偶数。(如果恰有一个字符出现的次数为奇数,可以转化到都是偶数的情况。)

    先考虑组合,再考虑顺序。

    组合:对于每个字符 \(c\),必须恰好选择 \(\dfrac{\operatorname{cnt}(c)}{2}\) 个字符在串的前半部分,剩下 \(\dfrac{\operatorname{cnt}(c)}{2}\) 个在串的后半部分。贡献为 \(\dbinom{\operatorname{cnt}(c)}{\operatorname{cnt}(c) / 2}\)

    顺序:组合方式固定后,对于前半部分,有 \((n/2)!\) 种排序方式。而后半部分的“样子”可以根据前半部分确定。由于字符的数量可能不止一个,所以即使后半部分的样子已经确定,它的方案数也不是 \(1\),而是每种排列出现的次数。换句话说,假设前半部分已经确定,则后半部分的方案数为 \(\prod_{c} (\operatorname{cnt}(c)/2)!\)

    综上所述,当所有字符出现的次数都为偶数时,回文串的个数为

    \[\prod_{c}\dbinom{\operatorname{cnt}(c)}{\operatorname{cnt}(c) / 2} \times (n/2)! \times \prod_{c} (\operatorname{cnt}(c)/2)! \]

    如果有一个字符出现的次数是奇数,我们可以选择这种字符中的一个放在串的正中间。设出现次数为奇数的字符为 \(ch\),则方案数在上式的基础上再乘上 \(\operatorname{cnt}(ch)\)

  4. [CSP-J 2022] 上升点列(A)

    唉唉,dp。

    以下把题目中的 \(k\) 成为 \(m\)

    先把所有点以横坐标为第一关键字,纵坐标为第二关键字,从小到大排序。

    \(f(i, k)\) 表示在前 \(i\) 个点中选点,并加入 \(k\) 个点时,能获得的最大长度。

    转移时,枚举所有在 \(i\) 左下方(即纵坐标和横坐标都不大于 \(i\) 的坐标)的点 \(j\)。设 \(i\)\(j\) 之间的曼哈顿距离为 \(dis\),那么我们用 \((dis - 1)\) 个新的整点填满 \(i\)\(j\) 之间的路径,尝试用 \(f(j, k - (dis-1)) + dis\) 更新 \(f(i, k)\)

    这里有一个问题:我们我们用 \((dis - 1)\) 个新的整点填满 \(i\)\(j\) 之间的路径,但图中本来就有其它的点,因此可能用少于 \((dis - 1)\) 个点就能填满 \(i\)\(j\) 之间的路径。那么这个转移方程错了吗?

    实际上它仍然是对的。这里的关键思想是:对于计算”最优值“的题目,在用某些方案去更新状态时,我们可能没有计算出这个方案的真实值,但我们能证明一定存在某种更优的方案,这种方案会覆盖掉原先那种无法计算出真实值的方案,因此不用去考虑它。这个思想在很多题目都有用到,不只是 dp(例如上文的[CSP-J2019 江西] 道路拆除 )。

    最后是一些细节:

    初始化:对于所有的点 \(1 \le i \le n\)\(f(i, 0) = 1\)

    答案统计:\(ans = \max_{1 \le i \le n, 0 \le k \le m}(f(i, k) + m - k)\)。加上 \(m - k\) 是考虑到了最后可能没有用完所有的点。这里仍然用到了上文中的思想——可能从某个点结束时,不能在不重合的情况下再多放出 \((m - k)\) 个点与它相连(比如这个点被包围了),但是这种情况一定不是最优的,所以不用考虑它。

posted @ 2024-09-29 18:19  DengStar  阅读(9)  评论(0编辑  收藏  举报