难得冬令营前面的一个放假,然后就开始咕咕咕了。。
算上之前做过的一个题和前几天超额计划的一个题,假装自己昨天做了 4 个题。
Luogu4363 [九省联考 2018] 一双木棋 chess
菲菲和牛牛在一块 \(n\) 行 \(m\) 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。
棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。
落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。
棋盘的每个格子上,都写有两个非负整数,从上到下第 \(i\) 行中从左到右第 \(j\) 列的格子上的两个整数记作 \(a_{i,j}\) 和 \(b_{i,j}\)。
在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的 \(a_{i,j}\) 之和,牛牛的得分是所有有白棋的格子上的 \(b_{i,j}\) 的和。
菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何?
\(n, m \le 10\)
状压
一年前我的讲课内容,直接贴图了。
Luogu4364 [九省联考 2018] IIIDX
给出一棵大小为 \(n\) 的森林,第 \(i\) 个点的父亲是 \(\left\lfloor\frac{i}{k}\right\rfloor\)(为 \(0\) 则代表为树根),同时给出一个长度为 \(n\) 的序列 \(\{d_i\}\),请将每个点赋一个权值,满足 \(val_i \ge val_{fa_i}\),输出字典序最大的方案。
\(n \le 5\times 10^5\)
数据结构
线段树
贪心
这题出来开始想简单,然后瞟了一眼题解发现 \(d_i\) 相等的时候不太行以外,其他的都是自己想出来的。
开始肯定有一个比较 native 的想法:
将 \(\{d_i\}\) 离散化,然后每个节点的子树都对应了一段连续区间,对于 \(1\sim n\) 依次确定区间,将区间最小的数作为区间端点值。
其实不要离散化,因为这个方法之适用于 \(\{d_i\}\) 互不相同的情况,于是就有 \(55\) 分了。
\(d_i\) 可能相同的情况不行的原因是对于某些节点,在选择 \(i\) 个和 \(i+1\) 个都是没有区别的,于是可以导致选择区间不连续。
然后想到我们在某个点确定了数字 \(x\) 后,就是相当于其子树只能选 \(\ge x\) 的权值,这个类似于将该点的权值与一段后缀区间进行匹配,进而,我们可以想到 Hall 定理,而在这个图上面(每个点连边方式都是一段后缀,并且要匹配若干个)的 Hall 定理(可能不严格是 Hall 定理?)就意味着我们可以类似 #2740. 「JOISC 2016 Day 4」最差记者 2 如下维护:
- 记 \(\{cnt_i\}\) 为 \(\{d_i\}\) 的出现次数
- 如果一个点 \(x\) 的权值是 \(y\),那么我们就将 \(cnt_y \gets cnt_y + siz_x\),然后求数组的最小后缀和,只有满足最小后缀和 \(\ge 0\) 才代表方案合法。
可以使用线段树维护,每次二分确定最靠后的合法位置。复杂度 \(\mathcal O(n\log^2 n)\),开了 O2 后可以跑过。
[代码](Luogu/P4364.cpp · yinjinrun/code-public-2 - 码云 - 开源中国 (gitee.com))
Luogu4365 [九省联考 2018] 秘密袭击 coat
给出一棵 \(n\) 个点的树,权值 \(\le w\),求每个连通块的第 \(k\) 大权值(如果没有则为 \(0\))之和 \(\bmod~64123\)。
\(1 \le n \le 1666, 1 \le k \le n, 1 \le w \le 1666\)
数据结构
线段树合并
拉格朗日插值
生成函数
神仙题。
当我推出了可以拉格朗日插值的时候,惊喜地发现我的复杂度是 \(\mathcal O(n^3)\) 的,然后点开题解发现还可以线段树优化。
首先我们可以转化一下问题,我们要求的是第 \(k\) 大,这个不太好维护,于是我们可以对答案进行差分,算出第 \(k\) 大 \(\ge t\) 的方案数,最后求和就行了。
然后可以考虑在整个连通块最浅的节点处计算答案,我们可以维护 \(f(x, t, i)\) 表示以 \(x\) 为根的节点,大于等于 \(t\) 的权值有 \(i\) 个的方案数,复杂度就是 \(\mathcal O(n^3 w)\) 的。
然后注意到有一维是背包的形式,我们可以将其写成生成函数的形式,这样就可以使用 NTT 等将复杂度降到 \(\mathcal O(n^2 w \log n)\),但是这个质数比较独特,可能需要其他的技巧优化复杂度,但是我不会。
这样下去显然没有进一步优化的空间,但是注意到最后我们的是一个 \(n\) 次多项式,于是我们可以考虑拉格朗日插值,代入 \(n + 1\) 个点值,然后复杂度就是 \(\mathcal O(n^3)\) 的。
这个时候我们拉格朗日插值是这么做的:
- 枚举 \(t \in [1, n + 1]\),设 \(f(x, t)\) 表示以 \(x\) 为根的子树,大于等于 \(t\) 对应的生成函数的值。
- 每次合并 \(x, y\) 子树的时候:
\(f(x, t) \gets f(x, t) \times f(y, t) + 1\)(加 1 代表可以选空的) - 也就是对应位置相乘。
- 那么最后答案就是每个子树所有 \(t\) 对应的权值之和。
然后,我们发现,对应位置相乘,就是线段树合并支持的操作!于是可以使用线段树合并进行优化。
现在想想我们的线段树合并要维护的操作:
- \(f\) 相乘
- \(f\) 加
我们可以维护标记 \((a,b)\) 代表 \(f \gets af + b\)。
同时,因为我们要对于每个子树求和,于是我们要维护一个 \(g(x, t)\) 表示 \(x\) 为根的子树相应 \(t\) 的权值之和,也就是每次 \(f\) 计算完毕后,让 \(g \gets g + f\) 即可。
于是我们对于 \(g\) 也要相应地维护权值 \((c, d)\) 表示 \(g \gets cf + g + d\)。
综合来说,我们要维护 \((a, b, c,d)\),代表 \((f, g) \gets (af + b, cf + g + d)\),至于合并两个标记 \((a, b, c, d), (a', b', c', d')\):
- \((f, g) \gets (af + b, cf + g + d)\)
- \((af + b, cf + g + d)\gets \left(a'(af + b) + b', c'(af + b) + (cf + g +d) + d')\right)\)
- 于是, \((a, b, c, d) + (a', b', c', d') \Rightarrow (aa', a'b+b', c'a+c, c'b+d+d')\)
然后还要注意线段树的初值是 \((1, 0, 0, 0)\) 就行了。
因为细节有点多,然后晚上比较犯困,于是上面这个代码是和题解 diff 了很多次后得出的,今天重写了一份(虽然没有太大的区别):代码 2
附:拉格朗日插值求出所有的系数
当初想了很久这个问题。。
我们拉格朗日插值的时候,从来都是求出第 \(k\) 项的具体值,而在本题中,我们要求出来的就是所有项的系数,我们可以使用背包 \(\mathcal O(n^2)\) 求出。
观察拉格朗日的式子:
\[f(x) = \sum_{i} y_i \prod_{i \neq j} \frac{x - x_j}{x_i - x_j} \]我们注意到底下的 \(\prod_{i \neq j} (x_i -x_j)\) 的处理是比较快的,我们要重点考虑上面的 \(\prod_{i\neq j} x-x_j\)。
注意到 \(i \neq j\),于是我们可以先忽略这个条件,预处理出 \(\prod_j x - x_j\) 的系数,这个可以用背包求出。
对于 \(i \neq j\) 的限制,我们使用的时候将整个数组反背包(就是集体除一个多项式)求出。