「CSP-J」做题记录
「CSP-J」做题记录
记号:
- A:自己做出来的。
- B:看题解提示做出来的。
- C:对着题解做出来的。
-
我们可以把问题转化一下:求出最少要留下多少边,使得从首都出发,能到达 \(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)\) 来更新最少剩余边数。那如果在两条路径分开之后,在某个地方又重合了呢?容易证明,在我们枚举点的过程中,一定可以找到一个更优的点来替换掉这种情况(此处有张图会更好理解,但我懒得画了),所以这种方法是正确的。
-
[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}\) (根据上文的不等式)。所以比较这两种情况即可。
-
正难则反,考虑计算回文串的个数,用 \(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)\)。
-
唉唉,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)\) 个点与它相连(比如这个点被包围了),但是这种情况一定不是最优的,所以不用考虑它。