IOI 2020 集训队作业胡扯「51, 100」

IOI 2020 集训队作业胡扯「1, 50」
IOI 2020 集训队作业胡扯「51, 100」(★)
IOI 2020 集训队作业胡扯「101, 150」

如果您点击了某个超链接,但是并没有发生任何变化,这意味着您可能需要在另外两章节中寻找对应内容。

表格

试题一 完成情况 试题二 完成情况 试题三 完成情况
cf549E cf674G arc103_f
cf594E agc034_f agc030_d
cf575E agc035_c agc026_f
cf607E agc038_e agc030_c
cf611G agc034_d agc024_f
cf571E cf696F arc093_e
cf573E cf704E arc103_d
cf627F agc035_d agc033_f
cf538G cf674D arc101_f
cf566C cf700E arc092_f
cf566E agc034_e agc022_d
cf613E agc033_e agc021_f
cf528C agc038_f agc029_e
cf611H agc036_d agc027_e
cf626G cf666D arc102_f
cf605E agc031_e agc028_d
cf536D agc027_f agc024_e
cf553E agc037_f agc029_c
cf571D cf708E arc093_f
cf603E agc036_e agc021_e
cf590E agc031_d agc026_e
cf587F cf685C arc096_e
cf587D cf674F arc091_f
cf575I agc035_f agc028_f
cf504E cf671E arc101_e
cf585F cf708D arc095_f
cf521D agc036_f agc028_c
cf585E agc032_c agc023_f
cf568C cf666E agc025_e
cf568E cf704C arc100_f
cf538H agc032_d agc024_d
cf582E agc039_e agc025_f
cf526F agc037_d agc020_e
cf521E agc030_f agc026_d
cf526G cf698D arc089_f
cf582D cf634F agc020_d
cf578F cf704B arc099_f
cf578E agc035_e agc025_d
cf516E agc030_e agc027_d
cf576E cf704D arc096_f
cf547E cf671D arc097_f
cf547D agc033_d agc031_f
cf575A cf639E agc039_f
cf559E agc037_e agc020_f
cf512D agc028_e agc022_f
cf506E cf639F agc039_d
cf576D agc029_f agc022_e
cf555E agc032_e agc023_d
cf506C cf679E arc098_f
cf516D agc032_f agc023_e

绿的表示主要没看题解,的表示主要看了题解。


2020-01-15

agc020_e

等价于计算有多少个编码方式,解码后能得到 \(S\) 的子集。

假设长度为 \(n\) 的字符串 \(s\) 的答案为 \(f(s)\),则可以列出两种转移方式:

  1. \(f(s) =_+ f(s[1 : n - 1]) \times (1 + s[n])\)
    表示:编码方式的最后一个字符为 01,去掉这个字符后,前面的方案数即为 \(f(s[1 : n - 1])\)
    而当 \(s[n] = 0\) 时,最后的字符只能填 0,有 \(1\) 种方案;否则可以填 01,有 \(2\) 种方案。

  2. \(f(s) =_+ f(s[1 : n - li]) \times f(\bigcap_{j = 1}^{i} s[n - lj + 1 : n - l(j - 1)])\)\(i \ge 2\)\(l \ge 1\)\(li \le n\))。
    表示:编码方式的最后一个字符为 ),也就是说最后一段是 (\(t\)x\(i\)),枚举长度 \(l = |t|\) 和重复次数 \(i\)
    后面的 \(t\) 需要满足解码后是 \(s\) 中最后 \(i\) 段长度为 \(l\) 的子串的交的子集,也就是 \(\bigcap_{j = 1}^{i} s[n - lj + 1 : n - l(j - 1)]\) 的子集。

你可能会认为这样子时间复杂度太大,但是题解告诉我们,记忆化搜索后,有用的状态数是 \(\mathcal O (2^{|S| / 8} + {|S|}^3)\) 的。每个状态可以花 \(\mathcal O (n^2)\) 的时间进行转移,反正就是跑过了。

时间复杂度为 \(\mathcal O ({|S|}^2 2^{|S| / 8} + {|S|}^5)\)评测链接

cf566C

注意到 \({|x|}^{1.5}\) 是下凸函数,也就是说每个位置都可以求出向最优解方向移动的倾向,也就是导数。

考虑点分树,从根开始利用导数的正负确定应该往哪个子树方向走,最多走 \(\log n\) 层。

不需要显式建出点分树。

时间复杂度为 \(\mathcal O (n \log n)\)评测链接

2020-01-16

cf587F

这题和 cf547E 极其相似,那题是问 \(s_k\)\(s_{l \sim r}\) 中的出现次数,这题是问 \(s_{l \sim r}\)\(s_k\) 中的出现次数。

\(\displaystyle \sum_{i = 1}^{n} |s_i| = l\),有 \(l = \Omega (n)\)

先建出 AC 自动机,然后考虑一下答案如何表示。

\(\mathrm{id}_{i, j}\)\(s_i[1 : j]\) 在 AC 自动机上对应的节点。
特别地,\(\mathrm{id}_i = \mathrm{id}_{i, |s_i|}\)\(s_i\) 在 AC 自动机上对应的节点。

则询问 \((l, r, k)\) 的答案可以表示为:
令 fail 树中的 \(\mathrm{id}_{l \sim r}\) 的子树的权值都加上 \(1\)(重复的加多次)。
则答案为 \(\mathrm{id}_{k, 1 \sim |s_k|}\) 的权值和。

还以为和 cf547E 一样能有简单做法,结果想了半天都没想到 \(\mathrm{polylog}\) 的做法,看了一下题解发现是根号的。

考虑根号分治,\(|s_k| \le T\) 的和 \(|s_k| > T\) 的询问分开处理。

对于 \(|s_k| > T\) 的串,这样的串不会超过 \(l / T\) 个,考虑对于每个串使用线性的时间处理:
先把 \(\mathrm{id}_{k, 1 \sim |s_k|}\) 的权值定为 \(1\),然后在 fail 树上做一遍子树和,求出每个点子树中的权值和。
然后对于关于 \(s_k\) 的所有询问,拆分左右端点并按升序排序,用一个指针扫过所有询问端点,并用 \(\mathrm{id}_i\) 的权值累加答案。
这一部分的时间复杂度为 \(\mathcal O (l^2 / T)\)

对于 \(|s_k| \le T\) 的串,每个询问考虑用 \(\mathcal O (|s_k|)\) 的时间进行处理:
对于每个询问拆分左右端点并按升序排序,用一个指针扫过所有询问端点,每处理一个,就把 fail 树上 \(\mathrm{id}_i\) 的子树的权值都加上 \(1\)
对于每个询问 \(s_k\),查询 \(\mathrm{id}_{k, 1 \sim |s_k|}\) 当前的权值并累加,就是该询问的答案。
子树加,单点查使用 DFS 序 + 分块实现(\(B = \sqrt{l}\)),这一部分的时间复杂度为 \(\mathcal O (n \sqrt{l} + qT)\)

\(T = \Theta (l / \sqrt{q})\) 可以取得最佳时间复杂度。

时间复杂度为 \(\mathcal O (n \sqrt{l} + q + l \sqrt{q})\)评测链接

2020-01-27

cf571E

记集合 \(\{a, a b, a b^2, a b^3, \ldots \}\)\(\langle a, b \rangle\),特别地,记 \(\{a\}\)\(\langle a, 1 \rangle\)

考虑合并 \(\langle a, b \rangle\)\(\langle c, d \rangle\),形成新的集合,可以证明这个集合也可以表示成等比数列形式。

令所有 \(n\)\(a, b\) 中涉及到的质数的集合为 \(P\),则可以把 \(a, b, c, d\) 表示为 \(|P|\) 维向量(第 \(i\) 个分量的大小为第 \(i\) 个质数在数值的质因数分解中的幂次)。

也就是要解 \(\vec{a} + k_1 \vec{b} = \vec{c} + k_2 \vec{d}\),其中 \(k_1, k_2\) 是非负整数。

考虑 \(\vec{b}\)\(\vec{d}\) 是否为零向量,以及是否线性相关。

如果至少一个为零向量,可以直接判断,如果不线性相关,可以解二元一次方程组,如果线性相关,需要解线性同余方程。

大分类讨论即可。

时间复杂度为 \(\mathcal O (n^2 \omega(v) \log v)\),其中 \(v\) 是值域,\(\omega(n)\) 表示小于等于 \(n\) 的正整数的不同质因数个数的最大值,评测链接

2020-01-28

cf590E

学习了一下偏序集上的最长反链求法。

\(l\) 为字符串长度之和。

先构造 AC 自动机,然后可以在 \(\mathcal O (l)\) 的时间内求出每个串在每个结束位置包含的最长的小串是哪一个。

注意这并不是全部的包含关系,所以还要用 Floyd 求出传递闭包,用 bitset 优化。

然后是偏序集上求最长反链(求方案),参考 [CTSC2008]祭祀river 的做法。

代码中使用了 Dinic 求二分图匹配。

时间复杂度为 \(\displaystyle \mathcal O \!\left( l + \frac{n^3}{w} + n^{2.5} \right)\),其中 \(w\) 为字长,评测链接

2020-01-29

agc028_c

与其设置 \(x \to y\) 这条边的权值为 \(\min(A_x, B_y)\),我们看成有两条边,权值分别为 \(A_x\)\(B_y\)。这样转化后,答案仍然相同。

我们考虑某种最终答案,假设走了 \(x \to y\) 这条边,
如果走的是权值为 \(A_x\) 的边,我们把这条边染红色
如果走的是权值为 \(B_y\) 的边,我们把这条边染蓝色

也就是说,红色边的边权等于它的起点的 \(A_x\)蓝色边的边权等于它的终点的 \(B_y\)

我们考虑最终的答案形成的环,要么全是边,要么全是边,要么交替。

这不是废话吗?为什么要分三类?

这是因为只有交替,才能够允许同时存在「入边和出边都是红色的点」和「入边和出边都是蓝色的点」。
也就是说,当且仅当交替时,才能任意选入边和出边的颜色,如果不是交替的,则颜色必须完全一样。

那么我们先让答案变成全选红色和全选蓝色\(\min\),也就是 \(\sum A_i\)\(\sum B_i\)\(\min\)

然后考虑交替时的答案怎么计算:

因为交替时,必然会出现入边为蓝色,出边为红色的点。我们枚举这样的一个点 \(i\) 之后,把它的 \(A_i\)\(B_i\) 都加进答案,只要在剩余的 \(2n - 2\)\(A_j\)\(B_j\) 中,选出最小的 \(n - 2\) 个,就一定能够组成合法的答案。

把标号和权值一起记下来排序,就能得到每个点的 \(A_i\)\(B_i\) 的排名,分类讨论一下不难得到答案。

时间复杂度为 \(\mathcal O (n \log n)\)评测链接

2020-01-30

arc097_f

我们的目标是把所有白点变黑。首先,特判掉没有白点,或者白点只有 \(1\) 个的情况。分别输出 \(0\)\(1\)

我们记 \({col}_i\) 为点 \(i\) 的颜色,如果点 \(i\) 为白色,则 \({col}_i = 1\),否则 \({col}_i = 0\)

剩下的情况中,我们把包含所有白点的极小连通块抽离出来(可以通过不断删除黑色叶子实现)。
显然,这个连通块形成了有 \(\ge 2\) 个点的一棵树。令连通块中的点数为 \(num\)

不难发现,最优解中,猫一定不会踏出这个连通块。
但是又必须经过连通块内的每个点(因为必须经过连通块里的所有叶子,连通块中的所有叶子都是白点)。

那么接下来,我们只考虑这个连通块,定义 \({deg}_i\) 为连通块中点 \(i\) 的度数(不考虑原树中的边)。

又有结论:猫不会经过一条边 \(\ge 3\) 次,也就是说只会经过 \(1\) 次或 \(2\) 次。
(这是因为多余的操作都可以简化成“改变当前点的颜色”的操作,一定不会更劣)

我们先假设:猫必须回到起点。

可以发现这时猫的起点对答案已经没有影响了。因为每条边都会被正向反向分别经过恰好 \(1\) 次。

也就是说,先规划好了路线,计算这个路线对点颜色的影响。在这之后再“插入”改变当前点颜色的操作。

那么显然,在这个情况下,如果 \({deg}_i\) 为奇数,则 \({col}_i\) 就会因为该点被到达了奇数次而发生改变,否则 \({col}_i\) 保持不变。

最终,答案就等于 \(2 \cdot (num - 1) + \sum {col}_i\),也就是 \(2\) 乘边数,加上 \({col}_i = 1\) 的点数,这些点需要额外使用一次操作。

问题在于:猫不一定要回到起点。

假设猫从 \(x\) 出发,最终到达了 \(y\)。令 \(x\)\(y\) 之间的边数为 \(len\)

则可以少走 \(len\) 条边,也就是不用从 \(y\) 再返回 \(x\) 了。

但是少走的这 \(len\) 条边,对 \(col\) 也有影响:
因为从 \(y\) 返回 \(x\) 的边少走了,所以 \(x\)\(y\) 路径上的点(除了 \(y\) 本身)的 \(col\) 都会发生变化。

实际上恰好有 \(len\) 个点的 \(col\) 发生了变化。
如果 \(col\)\(1\) 变成了 \(0\),可以少花一次操作。但是从 \(0\) 变成 \(1\) 的话,就要多花一次操作。

也就是说,平均算下来,如果原先的 \(col\)\(1\),可以少花两次操作;如果是 \(0\),则不亏不赚。

总的来说,就是这条路径,经过的 \({col}_i = 1\) 的点要尽量多(但是不包含终点)。

一个观察:叶子的 \(col\) 始终为 \(0\)(因为原先叶子的 \(col = 1\),但是叶子的 \(deg\) 也是 \(1\),所以抵消了)。

而这条路径自然是越长越好,肯定会延伸到叶子,所以包不包含终点也没有影响了。

树形 DP 计算经过的 \({col}_i = 1\) 的点最多的路径就行了。

假设最多经过 \(ans\)\({col}_i = 1\) 的点,则最终答案为 \(2 \cdot (num - 1) + \sum {col}_i - 2 \cdot ans\)

时间复杂度为 \(\mathcal O (n)\)评测链接

agc030_d

因为 \(N\) 很小,考虑直接枚举位置对 \(\langle i, j \rangle\)\(1 \le i < j \le N\))以统计逆序对。

考虑一个概率 DP:令 \(f(i, j)\)\(1 \le i, j \le N\))为当前时刻下\(A_i > A_j\) 的概率。
(这里假设对于 \(Q\) 个操作,每个操作都以 \(1 / 2\) 的概率执行)

那么最终时刻下,满足 \(i < j\)\(f(i, j)\) 之和,再乘以 \(2^Q\) 就是答案(期望的线性性)。

按顺序考虑每个时刻(操作),考虑新的 \(f(i, j)\) 和原先的比有什么变化。

可以发现只有 \(\mathcal O (N)\) 个位置会发生变化。具体地说,只有 \(i, j\) 有至少一个等于 \(X_i\)\(Y_i\) 时才有可能发生变化。

暴力转移即可。

时间复杂度为 \(\mathcal O (N (N + Q))\)评测链接

arc093_e

考虑原图的一棵生成树 \(T\),边权和为 \(S\)

对于一条非树边 \(e\),定义 \(v(e)\)\(W_e\) 减去「\(U_e, V_e\)\(T\) 上的路径上的最大边权」。

也就是说,\(v(e)\) 表示用 \(e\) 替换 \(T\) 中的一条边,形成新的生成树的最小代价。显然有 \(v(e) \ge 0\)

假设染色方案已确定,如何计算满足条件的最小生成树?

  • 如果 \(T\) 中的边不同色,则 \(T\) 就是合法的最小生成树,权值为 \(S\)
  • 否则 \(T\) 中的边都是同一种颜色,取 \(v(e)\) 最小的异色的 \(e\),则合法的最小生成树的权值为 \(S + v(e)\)
  • 如果不存在这样的 \(e\)(所有边全部同色),则不存在合法的生成树。

那么答案就很显然了,先把 \(X\) 减去 \(S\)

如果 \(X < 0\),则无合法解,输出 0

如果 \(X > 0\),则 \(T\) 必须同色,且 \(v(e) < X\) 的边都必须染相同颜色,\(v(e) = X\) 的边必须至少有一个染不同颜色。

如果 \(X = 0\),则是上面的答案的基础上,再加上 \(T\) 不同色,其它边任意选的方案数。

容斥一下答案就出来了。

时间复杂度为 \(\mathcal O (M \log M)\)评测链接

2020-02-01

agc024_d

观察样例,再自己手造几组数据,就可以发现,最终长成的树必然是:

  1. 以一个点为中心的放射状。
  2. 以一条边为中心的放射状(两侧对称)。

更具体地说,也就是把中心点或中心边「拎起来」,下面挂着的树形态,满足每个深度相同的子树都完全一致。

而这时,答案就为树的深度(假设中心点的深度为 \(1\),中心边的两端点深度为 \(1\))。

而叶子个数,就等于每一个深度的节点的,子节点个数的乘积(包括深度 \(1\),但不包括叶子所在的深度)。

那么我们枚举中心点,或者中心边,把原树「拎起来」,原树就变成了一个奇怪的形状。

那么显然我们需要补最少的点,对于每个深度,把子节点个数取 \(\max\) 再相乘,就得到最终的最少叶子个数了。

每个点和边都枚举一遍,取最优解。

时间复杂度为 \(\mathcal O (n^2)\)评测链接

arc091_f

这题真的好简单……

显然我们求一下每堆石子的 SG 函数就好了。

我们打表找规律,当 \(K = 1\) 的时候,就是普通的 Nim。如果 \(K \ge 2\) 会怎么样?

\(K = 4\) 为例:

\[\begin{bmatrix} 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 & 11 & 12 & 13 & 14 & 15 & 16 & 17 & 18 & 19 & 20 & 21 & 22 & 23 \\ \hline 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 2 & 1 & 0 & 2 & 3 & 1 & 0 & 2 & 4 & 3 & 1 & 0 & 5 & 2 & 4 & 3 \end{bmatrix} \]

不难发现规律:

\[\operatorname{SG}_k(n) = \begin{cases} 0 & , 0 \le n < k \\ n / k & , n \ge k \wedge n \bmod k = 0 \\ \displaystyle \operatorname{SG}_k \!\left(n - \!\left\lfloor \frac{n}{k} \right\rfloor\! - 1 \right) & , n \ge k \wedge n \bmod k > 0 \end{cases} \]

然而直接这样算有点慢,不难发现,如果按照 \(\displaystyle \left\lfloor \frac{n}{k} \right\rfloor\) 分段,则每一段内是循环的。

可以把第三行改写成:\(\displaystyle \operatorname{SG}_k \!\left( n - \!\left\lfloor \frac{\displaystyle n - \!\left\lfloor \frac{n}{k} \right\rfloor\! \cdot (k - 1)}{\displaystyle \left\lfloor \frac{n}{k} \right\rfloor\! + 1} \right\rfloor\! \cdot \!\left( \left\lfloor \frac{n}{k} \right\rfloor\! + 1 \right) \right)\)

这样子计算,可以证明会在 \(\sqrt{n}\) 次内结束。

时间复杂度为 \(\mathcal O (N \sqrt{A})\)评测链接

2020-02-02

agc035_c

\(N\)\(2\) 的次幂时无解,这是因为 \(N\) 的最高位无法被异或得到。

否则一定有解,构造如下(令 \(m\) 为小于等于 \(N\) 的最大的 \(2\) 的次幂,\(k\)\(N - m\)):

\(N\) 是偶数时才需要连 \((m+1) \leftrightarrow N\)\(k \leftrightarrow N'\)

时间复杂度为 \(\mathcal O (N)\)评测链接

2020-02-03

cf603E

考虑给定了边集后,如何判断是否存在合法的选边方案。

容易证明存在一种方案,当且仅当每个连通块的大小都是偶数。
(考虑每个连通块仅保留一棵生成树,再在生成树上自底向上选边)

所以先把 \(n \bmod 2 \ne 0\) 的情况判掉(全部输出 -1)。

那么相当于每次我们可以尝试不断把权值最大的边删去,使得删去后图的每个连通块大小仍为偶数。

加边删边时,使用 LCT 维护最小生成树即可。

判断一条边是否需要删除,需要用能够统计虚子树信息的 LCT,这里虚子树信息就是子树大小。

为了方便考虑,代码中在初始的时候就加上了 \(n / 2\) 条边,第 \(i\) 条连接 \(2i - 1\)\(2i\),权值为 \(\infty\)
这样做可以保证在一开始的时候每个连通块大小都是偶数,省去了不必要的特判,如果算出来答案为 \(\infty\),就输出 -1

时间复杂度为 \(\mathcal O (m \log m)\)评测链接

2020-02-04

agc034_e

既然所有棋子最终到达了同一个点,我们先考虑枚举这个点,记做 \(r\),以 \(r\) 为根建树。

\(s_i\) 表示 \(i\) 子树中的所有点 \(A_i\) 之和,也就是子树中的棋子个数;
\(w_i\) 表示 \(i\) 子树中的所有棋子到 \(i\) 的距离之和。

这样,\(s_i\)\(w_i\) 都可以很容易地计算。
(具体地说,\(\displaystyle w_u = \sum_{v \in \mathrm{sons}_u} w_v + s_v\)

考虑做题目中的操作会带来的影响,假设操作的棋子分别位于 \(x, y\)

  1. \(x, y\) 为祖孙关系。这个操作对 \(r\) 本身,以及 \(r\) 的任意一个子树方向\(w\) 值都不会产生影响(注意不是子树,而是这个子树对 \(w_r\) 产生的贡献)。
  2. \(x, y\)\(r\) 的不同子树中。这个操作会使 \(r\) 的那两个子树方向的 \(w\) 值各减去 \(1\)
  3. \(x, y\)\(r\) 的同一个子树中,但是不为祖孙关系。这个操作会使 \(r\) 的那一个子树方向的 \(w\) 值减去 \(2\)

可以发现:如果 \(w_r\) 为偶数,在所有子树方向的贡献中,最大的那一个,也不超过 \(w_r\) 的一半的话,就可以不断通过 2 操作把某两个子树方向的贡献减去 \(1\),最终使得 \(w_r\) 变成 \(0\)。也就意味着所有棋子都到达了 \(r\)。(具体方法是,每次都选择当前贡献最大的子树中的一个棋子进行操作)

但是如果贡献最大的那个子树,它的贡献超过了 \(w_r\) 的一半怎么办呢?这时就需要在这个子树中使用 3 操作以减小这个子树的贡献。可以发现这个贡献减得越小越好。

这启发我们定义 \(f_i\) 表示只操作 \(i\) 子树中的棋子,能够把 \(w_i\) 最小减少到多少。就是做操作后 \(w_i\) 的最小值。

这样一来,只要 \(f_r = 0\),就意味着可以把棋子都聚集到 \(r\) 上,且根据上面的过程,恰好花费 \(w_r / 2\) 步。
(因为没必要使用 1 操作,而 2, 3 操作都会让 \(w_r\) 减去 \(2\)

我们考虑递归地计算 \(f_i\)。要求 \(f_u\) 时,考虑 \(u\) 的每个子节点 \(v\)\(w_v\)\(f_v\)
同样地,考虑对 \(w_u\) 贡献最大的那个子树 \(v\),我们使用 3 操作,让它的 \(w_v\) 变成了 \(f_v\)
这样一来,若 \((f_v + s_v) \le w_u / 2\),则 \(f_u = w_u \bmod 2\),否则 \(f_u = (f_v + s_v) - (w_u - (w_v + s_v))\)

这样就可以在 \(\mathcal O (N)\) 的时间内计算最终聚集到点 \(r\) 的答案了。总时间复杂度为 \(\mathcal O (N^2)\),足以通过该题。

显然这个式子是可以换根 DP 的,所以代码中也就写了,时间复杂度变为 \(\mathcal O (N)\)

时间复杂度为 \(\mathcal O (N)\)评测链接

agc026_d

去年 CSP 前,做过一个比赛,出题人搬了这题,我打了一整场比赛把它切掉了,其他题没分(
PS:数据范围改成了 \(1 \le N \le {10}^5\)


注意:我的做法与题解的做法有较大出入。

我们首先考虑这样的 DP:令 \(dp(i)\) 表示前 \(i\) 列已经染色,其他列还未染色的方案数。
但是这样定义的状态是没法转移的。

为什么?我们先考虑一下转移的方式:

  1. 如果相邻的两个格子为同种颜色(#### 或竖着排列的),则它们所在的 \(2 \times 2\) 区域中的颜色将被唯一确定。
    ##
    ##
    ##
    ##
    或它们旋转 \({90}^{\circ}\) 的结果。
  2. 如果相邻的两个格子的颜色不同(#### 或竖着排列的),在不考虑其它限制的情况下,它们所在的 \(2 \times 2\) 区域中的颜色是有两种方案的。
    ##
    ##
    或其旋转 \({90}^{\circ}\) 的结果。

现在,考虑前 \(i - 1\) 列已经染色,第 \(i\) 列以及之后还未染色的情况。
那么第 \(i\) 列的染色情况,可以只由第 \(i - 1\) 列的染色情况确定。
下面举几个例子(假设第一列为第 \(i - 1\) 列,第二列为第 \(i\) 列):

  1.  ?
     ?
    #?
    #?
    #?
    #?
    #?
    #?
    ,这个情况下第 \(i\) 列有 \(8\) 种染色方案:最底下 \(6\)\(2\) 种,上面两个格子 \(2 \times 2 = 4\) 种。
  2.  ?
     ?
    #?
    #?
    #?
    #?
    #?
    #?
    ,这个情况下第 \(i\) 列有 \(4\) 种染色方案:最底下 \(6\)\(1\) 种,上面两个格子 \(2 \times 2 = 4\) 种。
  3. #
    #
    #?
    #?
    #?
    #?
    #?
    #?
    ,这个情况下第 \(i\) 列有 \(2\) 种染色方案。
  4. #
    #
    #?
    #?
    #?
    #?
    #?
    #?
    ,这个情况下第 \(i\) 列有 \(1\) 种染色方案。

可以发现,关键就在于第 \(i - 1\) 列的,最靠下的,上下相邻两个格子颜色相同的位置。
如果这个位置在第 \(i\) 列的范围内,则第 \(i\) 列的最底下 \(\min(h_{i - 1}, h_i)\) 个格子的颜色就会被唯一确定,否则恰有两种方案。
剩下 \(\max(h_i - h_{i - 1}, 0)\) 个格子可以任意染色。

可能可以考虑记状态 \(dp(i, j)\) 表示前 \(i\) 列已经染色,且第 \(i\) 列最靠下的上下相邻两个格子颜色相同的位置为 \(j\)
但是这样状态也太多了,也没法做。

最后我们考虑记状态 \(dp(i)\) 表示:前 \(i\) 列已经染色,且保证第 \(i\) 列任意两个相邻格子的颜色都不同的方案数。
也就是第 \(i\) 列颜色交错的方案数。这样令 \(h_{n + 1} = 1\),则 \(dp(n + 1) / 2\) 就是答案。

我们考虑转移,如果 \(h_{i - 1} \le h_i\),也就是第 \(i\) 列变高了,则 \(dp(i) = 2 \cdot dp(i - 1)\)
这是因为我们限制了第 \(i\) 列是交错的,又因为 \(h_{i - 1} \le h_i\),所以第 \(i - 1\) 列也必然是交错的,可以直接转移。

但是如果 \(h_{i - 1} > h_i\) 怎么办?这时限制第 \(i\)交错,不能保证第 \(i - 1\) 列也是交错的。

先小结一下:可以发现,如果第 \(x\) 列的最底下 \(w\) 个格子是交错的,那么对于 \(y = x - 1\)\(x + 1\),也就是 \(x\) 的相邻列,可以推出第 \(y\) 列的最底下 \(\min(w, h_y)\) 个格子是交错的。

这引出一个结论:如果第 \(x\) 列是交错的,则第 \(y\) 列是交错的充分条件是:对于 \(x \le i \le y\)\(h_i \ge h_y\)
换句话说,就是 \(h_y\)\(x, y\) 之间(包含 \(x, y\))的 \(h\) 的最小值。


回到 DP 上,仍然是要转移 \(dp(i)\),我们假设前一个一整列都是交错的列为第 \(j\) 列。

则这个 \(j\) 要满足 \(\displaystyle h_j < \min_{j < k < i} h_k\),且「\(h_j \ge h_i\) 或『\(h_j < h_i\)\(\displaystyle \min_{j < k < i} > h_i\)』」。

这等价于 \(j\) 是前 \(i - 1\) 列单调栈中的元素(我们维护 \(h\) 值严格递增的单调栈),且当加入 \(i\)\(j\) 被弹栈或 \(j\) 为弹栈后的栈顶(但不能弹出 \(h\) 值恰好等于 \(h_i\) 的元素)。

根据单调栈的结论,总转移数是 \(\mathcal O (N)\) 的,这是可以接受的。接下来要考虑转移的系数。


我们首先考虑第一类转移,也就是 \(j\) 为被弹栈的元素(\(h_j \ge h_i\))的转移:

我们考虑上图,\(j = 5\)\(i = 11\)

\(j\)\(i\) 之间的 \(h\) 值依次为 \(6, 10, 11, 8, 12, 10, 3\)

我们已知第 \(j\) 列是交错的,而之后的每一列都必须不是交错的。

如果出现了类似图二中的情况,也就是在“中间部分”(不包括 \(j\)\(i\) 的部分)出现了相邻两列颜色没有翻转的话,就会导致“中间部分”出现一整列都是交错的情况,不符合要求。

也就是说“中间部分”必须满足:每一列的颜色都和上一列的不同,除了最初的那一列(第 \(j + 1\) 列)。
又因为第 \(i\) 列的颜色也可以选择翻转或不翻转,所以这里总共贡献了 \(2^2 = 4\) 的系数。

考虑图三图四的上面的部分,因为不能让第 \(8\) 列出现一整列都是交错的情况,需要存在一行的颜色不翻转,这里有 \(2\) 种情况。
而更上面未染色的部分,每一段红色的线条都会产生 \(2\) 的贡献(可以选择翻转或不翻转)。

为什么有恰好 \(2\) 种情况呢?这是因为 \(h_8 - h_j = 8 - 6 = 2\)

这一部分的总贡献为 \(2^7 + 2^8\),实际上是一个等比数列的形式。
这个等比数列的首项为 \(2^{\mathrm{num1}}\),末项为 \(2^{\mathrm{num2} - 1}\)。总和就为 \(2^{\mathrm{num2}} - 2^{\mathrm{num1}}\)
这里就有 \(\mathrm{num2} = 9\),以及 \(\mathrm{num1} = 7\)

\(\mathrm{num1}, \mathrm{num2}\) 如何计算呢?

我们记 \(b_i\) 表示前 \(i\) 列的形如这样的红线个数。可以发现 \(\mathrm{num2} = b_{i - 1} - b_j\),而 \(\mathrm{num1} = \mathrm{num2} - (h_k - h_j)\)
其中 \(k\) 就为上一个被弹栈的元素(这里 \(k = 8\)),也就是满足 \(j < k\)\(h_k\) 最小的元素之一。

综上所述,\(j\)\(i\) 产生的贡献就为 \(4 (2^{\mathrm{num2}} - 2^{\mathrm{num1}})\) 倍的 \(dp(j)\)
(特殊情况是 \(j = i - 1\),因为“中间部分”完全消失了,所以不能套用上面的推导,这时贡献为 \(2\)


然后我们考虑第二类转移,也就是 \(j\) 为弹栈后的栈顶,且上一个被弹栈的元素的 \(h\) 值不等于 \(h_i\)

仍然是 \(i = 11\) 的情况,此时 \(j = 2\)

图二,同样地我们不能允许出现在“中间部分”的相邻两列颜色不翻转的情况。

特别地,如图三,我们需要的交错的高度不是 \(h_j\) 而是 \(h_i\),因为 \(h_i > h_j\)

图四,可以发现此时颜色不翻转的行,只有 \(1\) 种取值了,也就是 \(h_3 - h_i = 4 - 3 = 1\)

而上面的部分仍然和前一种情况类似,我们可以求出此时的 \(\mathrm{num2} = b_{i - 1} - b_j - (h_i - h_j)\),而 \(\mathrm{num1} = \mathrm{num2} - (h_k - h_i)\)
其中 \(k\) 的含义和前文相同,为上一个被弹栈的元素。

综上所述,\(j\)\(i\) 产生的贡献就为 \(4 (2^{\mathrm{num2}} - 2^{\mathrm{num1}})\) 倍的 \(dp(j)\)
(特殊情况是 \(j = i - 1\),因为“中间部分”完全消失了,所以不能套用上面的推导,这时贡献为 \(2\)


然而其实我们漏掉了一种情况,要是这样的 \(j\) 不存在呢?也就是不存在交错的前一列该怎么办?

其实这无关紧要,我们只要让 \(h_0 = 1\),然后设 \(dp(0) = 1\) 就行了,不影响后续计算。

时间复杂度为 \(\mathcal O (N \log \mathrm{MOD})\),其中 \(\log \mathrm{MOD}\) 为快速幂复杂度,评测链接

2020-02-05

arc103_d

令值域为 \(v\),本题中 \(v = {10}^9\)

每次操作,你必须让 \(x\) 坐标或 \(y\) 坐标增加或减少一个定值 \(d\)

令一个点 \((x, y)\) 的奇偶性为 \((x + y) \bmod 2\),可以发现能够操作到的点的奇偶性都相同,所以先把无解判掉。

好像没有什么特别的构造方法。我们先考虑二进制拆分。

但是搞了半天之后,发现二进制拆分好像只能做到 \(2 (\lfloor \log_2 v \rfloor + 1)\) 次操作。

然后我们惊奇地发现,\(2 (\lfloor \log_3 v \rfloor + 2)\) 好像恰好就是 \(40\) 啊。

所以我们考虑把坐标表示成三进制数,注意这里三进制的系数,应该是 \(0, 1, -1\) 三种。

那么我们令 \(m = 40\)\(d_1 \sim d_m\) 分别为 \(1, 1, 3, 3, 9, 9, 27, 27, 81, 81, \ldots\)
也就是对于每一个 \(0 \le i \le 19\)\(3^i\)\(d\) 中出现两次。
(如果所有点的奇偶性为 \(1\),则去掉一个 \(3^{19}\)

接下来构造解,每一位使用恰好两个 \(3^i\)

我们从低位到高位考虑,假设考虑到了第 \(k\) 位。记 \(x_k, y_k\) 分别表示 \(x, y\) 坐标第 \(k\) 位的值。

  1. \(x_k = 0, y_k = 0\)
    RL 操作,也就是让 \(x\) 减去 \(1\) 再加上 \(1\),也就是不变。
  2. \(x_k \ne 0, y_k \ne 0\)
    R/L 操作中的一个,让 \(x_k\) 变成 \(0\)
    U/D 操作中的一个,让 \(y_k\) 变成 \(0\)
  3. \(x_k \ne 0, y_k = 0\)
    如果 \(x_k = 1\),做 LL 操作,让 \(x_k\) 变成 \(3\)
    如果 \(x_k = -1\),做 RR 操作,让 \(x_k\) 变成 \(-3\)
    无论是哪种操作都需要进/借位,最后 \(x_k\) 还是变成了 \(0\)
  4. \(x_k = 0, y_k \ne 0\)
    类似上一种情况。

特别地,如果考虑到了第 \(k = 19\) 位:

  1. 点的奇偶性为 \(0\):只会出现上述情况中的 1, 2 两种。
  2. 点的奇偶性为 \(1\):只剩一个 \(3^{19}\) 了,\(x_k, y_k\) 也必然只有一个非 \(0\),做 R/L/U/D 操作中的一个即可。

因为 \(\lfloor \log_3 v \rfloor = 18\),所以可以证明在执行上述操作时,只会影响到第 \(0 \sim 19\) 位。

时间复杂度为 \(\mathcal O (N \log_3 v)\)评测链接


看了题解后发现我是睿智,可以用二进制的,而且只需要 \(32\) 次。

2020-02-06

cf553E

\(f(i, k)\) 为第 \(i\) 个点在 \(k\) 时刻,最佳策略下到达终点的代价期望值;类似定义 \(g(j, k)\) 表示第 \(j\) 条边的代价期望值。

\(f\)\(g\) 互相转移,以 \(k\) 为阶段可以发现都是从大往小转移。最终答案就是 \(f(1, 0)\)

固定 \(f(i, \ast)\)\(g(j, \ast)\),转移形式是一个卷积,用分治 FFT 优化即可。

一开始的边界条件要先跑一下最短路。

时间复杂度为 \(\mathcal O (n^3 + m t \log^2 t)\)评测链接

agc022_e

这道题挺神的,我尝试用比较好理解的方式解释一下:

我们考虑判断一个已知的串是否合法。

首先一个显然的事实:假设我们把串的某一位从 0 变成了 1,那么一定是变优了,反之一定是变劣了。

也就是说,单独修改某一位的优劣性,是可以简单判断的。

接下来我们列举一些操作的情况:
11a => 1
10a => a
01a => a
00a => 0
1ab => (a|b)
0ab => (a&b)

又有一结论:如果 \(S\) 形如 11...,那么一定合法,这是因为,只要把后面的部分缩起来,再缩 11a 得到 1 即可。

我们再考虑串形如 00... 时,因为迟早要对 00 进行操作,我们不妨直接考虑对 00 进行操作时:
假设串形如 00ab...,那么操作 00a 得到 0b...,操作 0ab 得到 0(a&b)...
显然前者不劣于后者,所以直接操作前者即可。也就是说 00a... == 0...

考虑串形如 01... 时,同样地,直接考虑对 01 进行操作时:
假设串形如 01ab...,那么操作 01a 得到 ab...,操作 1ab 得到 0(a|b)...
a=0b=1 时,前者不劣于后者。当 a=1b=0 时,两种操作分别得到 10...01...

到底是 10... 优还是 01... 优呢?这里我们先不作解答。

考虑串形如 10... 时:
假设串形如 10ab...,那么操作 10a 得到 ab...,操作 0ab 得到 1(a&b)...
a=1 时,前者不劣于后者。当 a=0b=0 时,后者不劣于前者。当 a=0b=1 时,两种操作分别得到 01...10...

又回到了比较 10...01... 的问题上。

我们考虑 10xy...01xy...

  1. 如果 x=0,则前者可以得到 0y...10...;而后者可以得到 0y...
    此时,前者不劣于后者。
  2. 如果 x=1,则前者可以得到 1y...;而后者可以得到 1y...01...
    如果 y=1,前者不劣于后者。
    如果 y=0,两者都能得到 10...,而后者还可以得到 01...
    但是不能无限地往后接 10 循环,最终一定会变成 10a01a,但是它们的结果确实是相同的,没有孰优孰劣。

所以结论是 10...01... 更优。

一个例子是:1000101001,前者是合法的串,而后者不是。

那么我们构造如下转移图:

其中绿边表示 \(0\) 的转移,红边表示 \(1\) 的转移,橙边表示 \(0, 1\) 都是这个转移。

然后在这个自动机上转移即可。最终答案为 111 上的方案数之和。

时间复杂度为 \(\mathcal O (|S|)\)评测链接

arc101_e

直接 DP 的话大概是 \(\mathcal O (N^3)\) 的,使用容斥原理:

要计算的就是 \(\displaystyle \sum_{S \subseteq E} {(-1)}^{|S|} f(S)\),其中 \(f(S)\) 表示强制不能覆盖到 \(S\) 中的边的方案数。

也就是把 \(S\) 内的边都删掉,原树被分割成了若干连通块,每个连通块内部连线的方案数。

显然一个大小为 \(n\) 的连通块,任意连线的方案数为 \(1 \cdot 3 \cdot 5 \cdot \cdots \cdot (n - 1)\)(如果 \(n\) 是偶数,\(n\) 是奇数的话显然没有方案)。

那么设状态 \(dp(i, j)\) 表示考虑 \(i\) 的子树,割掉若干条边,\(i\) 所在的连通块大小为 \(j\),的贡献总和(不算 \(i\) 所在连通块的贡献)。

转移也是显然的。

时间复杂度为 \(\mathcal O (N^2)\)评测链接

arc101_f

首先,每个机器人只会从它旁边的两个出口离开。

对于旁边只有一个出口的机器人,直接不管它就行,不会影响答案。

对于旁边有两个出口的机器人,我们只需要保存它到两个出口之间的距离。

上述处理都可以通过双指针来完成。

现在问题就变成了,给定 \(k\)\(0 \le k \le N\))个机器人,第 \(i\) 机器人到它左边和右边的出口的距离分别为 \(x_i\)\(y_i\)

我们把每个机器人画在坐标系中,第 \(i\) 个机器人的位置就是 \((x_i, y_i)\)

可以发现,相当于我们操控两条直线,初始时这两条直线的位置分别为 \(x = 0\)\(y = 0\),也就是在坐标轴上。

我们可以把竖线往右移动,把横线往上移动。如果线碰到了一个点,这个点就被这条线吃掉,然后消失。

问点被线吃掉的,不同的方案数。

我们考虑这两条线的交点形成的轨迹,可以发现,在轨迹上方的点是被竖线吃掉的,在轨迹下方的点是被横线吃掉的。

那么我们考虑统计这条轨迹穿过这些点的方案数。限制是轨迹必须是增函数。

我们把坐标离散化一下,用树状数组优化 DP 就可以做了。

具体地说,我们把所有点按照横坐标递增排序。然后考虑某条竖线上的点如何转移。

\(dp(i, j)\) 表示,考虑了横坐标 \(\le i\) 的点了,并且轨迹下的点的纵坐标最大值为 \(j\) 的方案数。

\(dp(i, j)\) 可以转移到 \(dp(i + 1, j)\)\(dp(i + 1, y)\)(存在点 \((i + 1, y)\) 满足 \(y > j\))。

用树状数组维护。

时间复杂度为 \(\mathcal O (M + N \log N)\)评测链接

2020-02-07

arc103_f

假设满足条件的树为 \(T\),我们考虑 \(T\) 的一些性质。

首先 \(T\) 只有一个重心,因为如果有两个,那么它们两个的 \(D\) 值就应该相同,与题意矛盾。

显然重心就是 \(D\) 值最小的那个点。

\(T\) 以重心为根,容易发现,任何一个非根节点的 \(D\) 值都大于它的双亲节点的 \(D\) 值。

我们选取 \(D\) 最大的那个点 \(u\),显然它必须是叶子。

我们可以计算出它的双亲节点的 \(D\) 值应该恰好为 \(D_u - N + 2 \cdot \mathrm{siz}\),其中 \(\mathrm{siz}\)\(u\) 的子树大小(此时为 \(1\))。

那么就可以唯一确定它的双亲节点是哪一个。

然后把该点“删去”,并让它的双亲节点的 \(\mathrm{siz}\) 加上 \(1\)

重复 \(n - 1\) 次这个过程。就可以确定出 \(T\) 的形态。

也就是说,满足条件的 \(T\) 其实是唯一的。

这时我们再 DFS 检查一下是否确实满足条件即可。

时间复杂度为 \(\mathcal O (N \log N)\)评测链接

agc020_d

首先我们可以得出:最短的连续段长度等于 \(\displaystyle \left\lceil \frac{\max\{A, B\}}{\min\{A, B\} + 1} \right\rceil\! = \!\left\lfloor \frac{A + B}{\min\{A, B\} + 1} \right\rfloor\),令这个值为 \(K\)

观察 \(A \ge B\) 的情况(留作练习,请读者自行完成)(大雾)

可以发现,一组 \(A, B\) 的答案,就是当 \(A = (B + 1) K\) 时的答案(形如 \([B \cdot (K \cdot \texttt{"A"} + \texttt{"B"}) + K \cdot \texttt{"A"}]\)),
去掉靠后的恰好 \((B + 1) K - A\)\(\texttt{"A"}\) 得到的,令这个值为 \(\mathrm{del}\)

但是并不一定是去掉最后 \(\mathrm{del}\)\(\texttt{"A"}\),考虑 \(A = 8, B = 6\) 的情况:\(\texttt{"AABAABAABABABB"}\)
它就是 \(A = 14, B = 6\) 的情况:\(\texttt{"AABAABAABAABAABAABAA"}\) 去掉 \(6\)\(\texttt{"A"}\) 得到的,但是不是最后 \(6\) 个。

这是因为如果去掉了最后 \(6\) 个,就会有 \(3\)\(\texttt{"B"}\) 形成连续段,与「连续段长度不大于 \(2\)」冲突。

也就是说,贪心地去掉尽可能靠后的 \(\mathrm{del}\)\(\texttt{"A"}\),但是不形成 \((K + 1) \cdot \texttt{"B"}\) 的连续段。

讨论一下就可以得到结果了。

对于 \(A < B\) 的情况类似,是 \(B = (A + 1) K\) 时的答案(形如 \([A \cdot (K \cdot \texttt{"B"} + \texttt{"A"}) + K \cdot \texttt{"B"}]\)),
去掉尽可能靠前(不是靠后)的若干个 \(\texttt{"B"}\) 得到的,类似做就行了。

时间复杂度为 \(\mathcal O (Q (D - C + 1))\)评测链接

2020-02-08

arc099_f

考虑记前缀和信息 \((\Lambda_i, \delta_i)\) 表示依次吃掉 \(1 \sim i\) 的所有字符后,得到的序列和指针 \(P\) 的位置。

那么两信息的合并:\((\Lambda_1, \delta_1) \circ (\Lambda_2, \delta_2) = (\Lambda_1 + \Lambda_2 \gg \delta_1, \delta_1 + \delta_2)\)

我们记 \(h_i\)\(\displaystyle \sum_{p} \Lambda_i[p] \beta^p\)

则有 \((h_1, \delta_1) \circ (h_2, \delta_2) = (h_1 + h_2 \beta^{\delta_1}, \delta_1 + \delta_2)\)

考虑 \(g = h_n\),一个区间 \([i, j]\) 的信息等于 \(g\) 当且仅当 \(h_{j - 1} + g \beta^{\delta_{j - 1}} = h_i\)

那么我们从后往前枚举 \(j\),维护一个 \(h_i\) 的桶,以统计答案。

\(h\) 哈希一下就可以存进桶里了,为了防止冲突需要使用双哈希。

时间复杂度为 \(\mathcal O (N \cdot \mathcal T (\mathrm{hash}))\)评测链接

agc031_d

根据题意,我们可以得到 \(a_i = a_{i - 1} {(a_{i - 2})}^{-1}\)。其中 \(q p\) 表示置换的复合,满足 \({(q p)}_i = q_{p_i}\)

\(a_0\)\(a_{11}\) 列出,可得:

\[\begin{array}{rrcl} (a_0) =& & q^{-1} p &\\ a_1 =& & p & \\ a_2 =& & q & \\ a_3 =& & q p^{-1} & \\ a_4 =& & q p^{-1} q^{-1} & \\ a_5 =& & q p^{-1} q^{-1} p q^{-1} & \\ a_6 =& (q p^{-1} q^{-1} p) & q^{-1} p & (p^{-1} q p q^{-1}) \\ a_7 =& (q p^{-1} q^{-1} p) & p & (p^{-1} q p q^{-1}) \\ a_8 =& (q p^{-1} q^{-1} p) & q & (p^{-1} q p q^{-1}) \\ a_9 =& (q p^{-1} q^{-1} p) & q p^{-1} & (p^{-1} q p q^{-1}) \\ a_{10} =& (q p^{-1} q^{-1} p) & q p^{-1} q^{-1} & (p^{-1} q p q^{-1}) \\ a_{11} =& (q p^{-1} q^{-1} p) & q p^{-1} q^{-1} p q^{-1} & (p^{-1} q p q^{-1}) \\ \end{array} \]

所以是有个长度为 \(6\) 的循环节。

\(z = q p^{-1} q^{-1} p\),则 \(a_K\) 可以表示为 \(z^{K \div 6} a_{K \bmod 6} {(z^{-1})}^{K \div 6}\)

时间复杂度为 \(\mathcal O (N \log K)\)评测链接

cf587D

容易发现这是一个 2-SAT 的形式。

要求删除 \(t\) 尽量小的边,那就先二分答案。

不过还是要考虑建图的问题。

如果直接建图的话,会发现每个点周围的边都会互相影响,也就是删掉其中一条就不能删另一条。

直接建边的话要建 \(\mathcal O ({deg}^2)\) 条。

其实限制就是,一个点周围的边,最多删一条。

那么我们再在 2-SAT 模型中新建若干个变量,\(s_i\) 表示前 \(i\) 条边是否被删去。

如果 \(s_i = 1\),那么就有 \(s_{i + 1} = 1\)\(a_{i + 1} = 0\)

如果 \(a_i = 1\),那么就有 \(s_i = 1\)

大概是个链前缀和的形式。

这样子边数就是线性的了。

时间复杂度为 \(\mathcal O (m \log m + m \log t)\)评测链接

cf674F

这里我就抄 CMXRYNP 的题解了。

从能够得到的信息考虑。

最多有 \(\min\{p, n - 1\}\) 只熊要去睡觉,我们先让 \(p\)\(n - 1\)\(\min\)

那么对于每只熊,我们可以知道它有没有去睡觉,如果有可以知道它在第几晚去睡觉的。

所以最多的情况数就是:

\[\sum_{k = 0}^{p} \binom{n}{k} i^k \]

也就是枚举 \(k\) 只熊去睡觉了,然后 \(i\) 是天数。

这是桶数量的一个上界。因为再怎么改变策略最后也只有这么多种情况。

我们可以证明这个上界是可以被达到的。

把所有情况编号,对于第 \(x\) 种情况,令没有去睡觉的熊不碰第 \(x\) 个桶,在第 \(a\) 天去睡觉的熊恰好在第 \(a\) 晚去喝第 \(x\) 个桶里的饮料。

这样子如果第 \(x\) 桶里是酒,就恰好会生成这种情况,所以每种答案对每种情况是一个满射,然而它们数量相同,所以是一一对应的。

所以只要求出这个多项式的系数就行,系数就是组合数模 \(2^{32}\),记一下 \(2\) 的次数,递推一下就行。

时间复杂度为 \(\mathcal O (p \log \mathrm{MOD} + q \cdot p)\),其中 \(\log \mathrm{MOD}\) 为快速幂复杂度,评测链接

agc024_e

相当于是,从一个空串开始,每次往里面加入一个 \([1, K]\) 之间的字符,加入 \(N\) 次,使得字符串的字典序递增。

先把每个串的末尾加上字符 \(0\)

可以发现,加入字符(假设我们在字符 \(y\) 前插入字符 \(x\))后字典序递增,当且仅当:

  1. \(x > y\)
  2. \(x = y\),且 \(x > y\) 之后第一个不同的字符。

我们插入的时候,只关心字符串是否相同,不关心插入的位置。

所以假设是第二种情况,我们可以把插入的位置往后挪到那个不同的字符之前。

这样子既不会统计到重复的串,又避免了难考虑的 2 情况,一举两得。

现在只需要考虑 1 情况,也就是每次插入的字符必须插入在一个比它小的字符之前。

我们可以把插入的形式抽象化为一棵树:
根节点为 \(0\),权值也为 \(0\)
假设第 \(i\) 次在字符 \(y\) 之前插入了字符 \(x\),如果 \(y\) 是在第 \(j\) 次插入的,就令 \(i\)\(j\) 的儿子,权值为 \(x\)

可以发现这样的树,只需要满足:节点编号为 \(0 \sim N\),节点权值为 \(0 \sim K\),且孩子节点的编号和权值,要分别大于当前节点的编号和权值。

考虑令 \(dp(i, j)\) 表示,一棵 \(i\) 个点的树,节点编号为 \(0 \sim i - 1\),根节点权值为 \(j\),且满足上述条件的方案数。

有转移:\(\displaystyle dp(i, j) = \sum_{k = 1}^{i - 1} \binom{i - 2}{k - 1} dp(i - k, j) \sum_{j < x \le K} dp(k, x)\)

组合意义是:考虑编号为 \(1\) 的节点,它一定是根节点的孩子,且形成一个子问题,枚举 \(1\) 节点的子树大小,假设为 \(k\),将除了 \(0, 1\) 之外的 \(i - 2\) 个编号分配给除了 \(1\) 之外的 \(k - 1\)\(1\) 的子树中的点,这里贡献一个 \(\displaystyle \binom{i - 2}{k - 1}\);除了 \(1\) 子树外的大小为 \(i - k\),这里贡献一个 \(dp(i - k, j)\)\(1\) 节点的权值为 \((j, K]\) 中的整数,这里贡献一个 \(\displaystyle \sum_{j < x \le K} dp(k, x)\)

后一个和式用后缀和优化,状态转移的总时间复杂度为 \(\mathcal O (N^2 K)\)

答案就为 \(dp(N + 1, 0)\)

时间复杂度为 \(\mathcal O (N^2 K)\)评测链接

2020-02-10

cf538G

通过坐标变化,把曼哈顿距离转成切比雪夫距离。

也就是说四个方向 RLUD,原本是横纵坐标选取其中一个加减 \(1\),现在变成可以分别确定横纵坐标是加还是减。

所以这就变成了一个一维的问题,好考虑一些。具体地说,只要把 \((x, y)\) 变成 \((x + y, x - y)\) 就行。

接下来考虑一维问题,只要分别解决了两个一维问题,显然就可以拼成答案。

假设操作序列为 \(c\),则 \(c\) 是个 \(\pm 1\) 串。通过 \(x_i \gets (x_i + t_i) / 2\),可以把 \(c\) 转成 \(01\) 串。

则我们考虑 \(c\)\(01\) 串的情况,令 \(s\)\(c\) 的前缀和。
则有 \(s_i \le s_{i + 1} \le s_i + 1\)

考虑每个时刻,还有 \(x_i = \lfloor t_i / l \rfloor s_l + s_{t_i \bmod l}\)

\(s = s_l\),如果确定了 \(s\),就可以直接判断是否合法了。
具体的说,根据获得的 \(n\) 个时刻的信息,可以确定出 \(s_i\) 中一些位置的值了,然后根据 \(s_i \le s_{i + 1} \le s_i + 1\) 进一步判断。

但是现在不知道 \(s\),如何求出 \(s\) 呢。

我们把所有信息:\(c_i s + s_{p_i} = x_i\) 按照 \(p_i\) 从小到大排序。
\(c_i = \lfloor t_i / l \rfloor\)\(p_i = t_i \bmod l\)

不过在排序之前,要在这些信息里加上两条:\(0 s + s_0 = 0\)\((-1) s + s_l = 0\)

然后考虑相邻的两条信息,就可以列出不等式确定 \(s\) 的范围。

最后求得的 \(s\) 是一个区间,任取里面任何一个值都可以。

具体证明我也不太懂,反正 AC 了(

其它实现细节见代码。

时间复杂度为 \(\mathcal O (n \log n + l)\)评测链接

agc035_d

可以发现 \(A_1\)\(A_N\) 没啥用,不用考虑它们,然后最后加到答案里去就行。

那也就是说,现在有 \(N - 2\) 个数排成一行,你每次可以删掉其中一个,它就会加到左右两边去。

特别的,如果它在最左边,它就会被加到一个变量 \(L\) 上,如果它在最右边,它就会被加到一个变量 \(R\) 上。

最后要让 \(L + R\) 最小。

这时可以考虑倒着做。假设最后一个删掉的元素,是 \(i\)

那么 \(i\) 左边的数,一部分扔到 \(L\) 里了,一部分扔到 \(i\) 上了,\(i\) 右边的数,一部分扔到 \(R\) 里了,一部分扔到 \(i\) 上了。

然后删除 \(i\) 本身,就有那些扔到 \(i\) 上的数,以及 \(i\) 本身,都会被加到 \(L\)\(R\) 上。

那么我们假设,\(i\) 左边的数删除后,加到 \(i\) 上,总共加了 \(x\)。那么这 \(x\) 最后产生的贡献就是 \(2x\),因为加到了 \(L\)\(R\) 上。

右边同理,只不过换了个方向,也是两倍贡献。

既然倒着考虑了,那就要想到区间 DP。我们观察 \(i\) 左边的区间,这段区间中的数,加到左边会对总答案贡献 \(1\) 倍,但是加到右边会贡献 \(2\) 倍。

于是定义如下状态:\(dp(l, r, cl, cr)\) 表示考虑区间 \([l, r]\) 中的数,把它们删除后,会对总答案贡献 \(cl \cdot L + cr \cdot R\),要使这个贡献最小。

则最终答案为 \(dp(2, N - 1, 1, 1) + A_1 + A_N\)

有转移:

\[dp(l, r, cl, cr) = \min_{i = l}^{r} [ dp(l, i-1, cl, cl + cr) + dp(i + 1, r, cl + cr, cr) + (cl + cr) A_i ] \]

特别地,如果 \(l > r\),则 DP 值为 \(0\)

容易发现,DP 状态数的上界是 \(\mathcal O (N^2 2^N)\),因为区间只有 \(\mathcal O (N^2)\) 对,而后面的系数的增长可以看作一个 \(N\) 层的二叉树的形态。

经过一些精细计算,其实 DP 状态数和转移数只有 \(\mathcal O (2^N)\),这里就略去不证了。

时间复杂度为 \(\mathcal O (2^N)\)评测链接

agc033_e

不失一般性,我们假设 \(S[1] = \texttt{R}\),如果不成立则把两种颜色互换即可,不影响答案。

因为一开始就必须走红弧,所以环上不能出现相邻的蓝弧。也就是说,环上的每一段蓝弧的长度均为 \(1\)

如果 \(S\) 全部都是 \(\texttt{R}\),则不需要其他限制了,答案就为 \(2F_{N - 1} + F_N\)\(F\) 为斐波那契数列,\(F_0 = 0, F_1 = 1\))。

否则至少有一个 \(\texttt{B}\),初始的一段 \(\texttt{R}\) 后必然会跟着一个 \(\texttt{B}\),所以那时必须要走到蓝弧旁边。

由此可得,一定不会出现一段连续的红弧,满足长度为偶数。也就是说每段连续的红弧的长度一定是奇数。

如果出现了长度为偶数的红弧,则如果一开始的位置在这段弧上,且到两端的蓝弧的距离的奇偶性和 \(S\) 中第一段 \(\texttt{R}\) 的长度不一样,就一定不可能在 \(\texttt{R}\) 结束时到达蓝弧旁边(注意到因为长度是偶数,才有到两端的蓝弧的距离的奇偶性相同。如果长度为奇数,能保证恰好有一端距离的奇偶性与 \(S\) 中第一段 \(\texttt{R}\) 的长度相同)。

进一步地,假设 \(S\) 中第一段 \(\texttt{R}\) 的长度为 \(l_1\),则每段红弧的长度,不能超过 \((l_1 + [l_1 \bmod 2 = 0])\)(因为恰好有一端是可行的,到那一端的距离不能太大)。

接着,考虑 \(S\) 之后的每一段连续的 \(\texttt{R}\)

如果这一段 \(\texttt{R}\) 之后没有接着一个 \(\texttt{B}\),也就是说它在 \(S\) 的末尾,那么对它就没有限制。

否则,考虑它的长度,假设为 \(l_i\)。因为这一段 \(\texttt{R}\) 的上一个字符必然也是 \(\texttt{B}\)(不是第一段了),所以一开始时必然是在某一段红弧的端点上。如果 \(l_i\) 为奇数的话,就要走到对面的端点上才行,否则一直在相邻的红弧上反复横跳就行。也就是说,如果 \(l_i\) 为奇数的话,这一段红弧的长度最长不能超过 \(l_i\);如果是偶数的话不产生影响。当然,因为起点是任选的,所以每一段红弧也都具有了这个性质。

总的来说,就是说每一段红弧的长度被限制了,最小是 \(1\),最大不妨令它为 \(k\),且要是奇数。然后要计算形成一个环的方案数。

我们把一段红弧,和它在逆时针方向的第一个蓝弧,算作一段,这样每一段的长度就必须是 \(2 \sim (k + 1)\) 之间的偶数,所以 \(N\) 也必须是偶数。

环上的情况不好考虑,必须要转化成序列。

我们考虑第一个弧所在的那一段,假设那一段的长度为 \(x\),则有 \(x\) 种方法旋转,使得第一个弧仍然在那一段中。

那么也就是说,对于所有的权值是 \(\le k\) 的正偶数,总和为 \(N\) 的序列 \(A\),每一个序列会为答案贡献 \(A_1\) 种方案。

也就是枚举 \(A_1\),然后计算总和为 \(N - A_1\) 的序列的数量,乘以 \(A_1\) 后贡献给答案。

总和为 \(i\) 的序列的个数很好算,只要枚举最后一个元素是多少就行了,有转移:\(\displaystyle f(i) = \sum_{j = 2}^{k} [j \bmod 2 = 0] f(i - j)\)

用前缀和优化一下就完事了。

时间复杂度为 \(\mathcal O (N + M)\)评测链接

2020-02-11

cf634F

如果固定上下边界,那么中间的点,按照纵坐标排序,就可以统计答案了。所以这样子是 \(\mathcal O (r^2 n)\) 的。

那我们固定上边界,往下推下边界呢?那就是变成每次插入一个点,会影响它周围的 \(k\) 个点对答案的贡献。

但是动态插入,比较不好维护。那我们就从下往上推下边界,现在就变成删除,可以用链表快速定位和找周围的 \(k\) 个点。

时间复杂度为 \(\mathcal O (n \log n + r^2 + r n k)\)评测链接

2020-02-12

cf666E

因为不会 SAM,所以用 SA。

我们考虑 Height 数组的 Kruskal 重构树,其实是和后缀树等价的。

那一次询问就是查询一棵子树中,出现次数最多的颜色,以及它出现的次数。

线段树合并即可(好像是我第一次写线段树合并)。

时间复杂度为 \(\mathcal O ((l + q) \log m)\),其中 \(\displaystyle l = |s| + \sum |t_i|\)评测链接

cf611H

可以发现只要是无序对 \((a_i, b_i)\) 相同的边,都可以只看做一类,这样就只有最多 \(6 (6 + 1) / 2 = 21\) 类边。

同时位数相同的点,也可以看作一类,这样只有最多 \(6\) 类点。

\(m = \lfloor \log_{10} n \rfloor + 1\),点的类数就为 \(m\),边的类数就为 \(m (m + 1) / 2\)

可以发现不同种类的点,不管怎么样也还是要连接起来的。

那么先特判一下 \(m = 1\) 的情况,然后可以证明一个结论:存在一种方案,满足:

  • 每一类点都选出一个“关键点”,例如第 \(i\) 类点的关键点编号可以为 \({10}^{i - 1}\)
  • 只考虑这 \(m\) 个关键点,它们形成的导出子图,是一棵树,也就是一个 \(m\) 个点 \(m - 1\) 条边的树连接了所有“关键点”。
  • 其它所有点只与“关键点”连接,也就是不存在“非关键点”之间的连边。

详细证明这里从略。

那么,我们考虑枚举连接所有“关键点”的树形态,比如使用 Prüfer 序列枚举,这部分的时间复杂度为 \(\mathcal O(m^{m - 2})\)

枚举完成后,对应种类的边就用掉了对应条,这里记得先扣掉。

然后考虑每一条边 \((u, v)\),可以是 \(u\) 类“非关键点”连到 \(v\) 类“关键点”上,也可以是 \(v\) 类“非关键点”连到 \(u\) 类“关键点”上。

总之,一条边 \((u, v)\) 将会把 \(u\) 类或者 \(v\) 类的“非关键点”的剩余个数减去 \(1\)

这样一来就可以转化为一个带权(重数)二分图完美匹配的模型。

具体地说,左侧有 \(m (m + 1) / 2\) 个点,表示每一类边,右侧有 \(m\) 个点,表示每一类点。

左侧的每个点,带的权值(重数)为剩余的对应类型的边的数量。

右侧的每个点,带的权值(重数)为剩余的对应类型的点的数量。

不难发现这两个数量之和相等。左侧的每个点,假设它对应的边的类型为 \((u, v)\),它向右侧的 \(u, v\) 类点对应的点分别连边。

使用网络流可以解决带重数的二分图匹配问题,这里写个 Dinic 水过去。

Dinic 跑完之后也可以直接构造方案了。

时间复杂度为 \(\mathcal O (m^{m + 4})\)评测链接

2020-02-13

cf613E

对于 \(|w| \le 2\) 的情况,我们进行特判,这是为了之后写起来分类讨论可以简洁一些。

观察一下最终的行走方式可能会变成啥样:

很多情况下,会变成这个样子。

注意到可以分成三段,左边一个 U 形,中间一个只会向右走的形状,右边又一个 U 形。

啊,为啥说中间是只会向右走?因为我们是这么钦点的,当然也可能是从右边出发往左走,这时只要把 \(w\) 反转,再求一次就行。

我们可以处理出,从一个地方分段,会不会产生向左的,长度为某个值的 U 形。

这可以通过预处理 LCP 做到。

同理可以处理出,从一个地方分段,会不会产生向右的,长度为某个值的 U 形。

处理上述两个数组,它们就能够作为第一部分和第三部分。

我们把第二部分接在第一部分后,记 \(f(i, j, k)\) 表示,当前第二部分走到了 \((i, j)\),并且匹配了 \(w\) 的前 \(k\) 个字符,并且不是从同一列走来的方案数。

类似地,记 \(g(i, j, k)\) 为必须从同一列走来的方案数。则 \(f, g\) 之间可以互相转移,这部分可以 \(\mathcal O (n |w|)\) 处理。

然后考虑在 DP 到 \((i, j, k)\) 时,接上第三部分即可,可以直接判断接不接得上。

当然还有一些其他情况没有讨论的,比如三个部分中的某一部分并不存在,甚至是两个部分不存在之类的,仔细讨论一下即可。

注意要不重不漏,特别注意 \(w\) 反转后不要统计重复了。

时间复杂度为 \(\mathcal O (n |w|)\)评测链接

cf566E

如果两个集合的交为 \(2\),则交出来的这两个点,之间一定有连边。

这样可以确定树中所有非叶子节点之间的连边情况。

先特判非叶子节点数为 \(0, 1, 2\) 的情况。

\(0\) 的话就是 \(n = 2\);为 \(1\) 的话就是菊花,每个集合大小都是 \(n\);为 \(2\) 的话就是有恰好两个集合大小是 \(n\)

现在非叶子节点数至少是 \(3\)。那么我们需要确定每个叶子挂在了哪个非叶子上。

注意到我们在给非叶子节点连边的时候,就可以处理出每个非叶子节点,与其相连的非叶子节点的集合,也就是距离 \(\le 1\) 的集合。

那么我们依次考虑每个叶子,它对应的集合就是所有集合中,包含这个叶子的,大小最小的那个。

在这个集合中,去掉所有叶子节点,就得到了与它相连的非叶子节点的邻接非叶子节点集合。

再枚举每个非叶子节点,就可以判断具体是和哪一个非叶子节点相连的了。

时间复杂度为 \(\displaystyle \mathcal O \!\left( \frac{n^3}{w} \right)\),其中 \(w\) 为字长,评测链接

cf573E

考虑一个贪心策略:一开始选空集,然后每次选一个不在集合中的数加入集合,具体选哪个数呢?选择让新的答案最大的数即可。

然后集合大小从 \(0\) 逐渐增大到了 \(n\),得到了 \(n + 1\) 个答案,我们选取其中最大的一个输出。

我们发现这样做成功 TLE 了(悲),但是并没有 WA,说明贪心是对的(确信)。

具体证明请下载 徐翊轩的题解 查看。

那么我们只需要快速维护这个贪心,具体地说,每个位置有一个权值 \(b_i\) 和一个固定的值 \(a_i\),需要支持四种操作:

  1. 前缀 \(b_i\) 加相同值。
  2. 后缀 \(b_i\)\(a_i\)
  3. 查询 \(b_i\) 的全局最大值。
  4. 删除一个位置。

一般线段树没法做,我们考虑分块。(其实这是一种经典分块类型)

\(\sqrt{n}\) 个元素分一块,那对于每一块就要实现:

  1. 整体加。
  2. 整体加 \(a_i\)
  3. 查询整体最大值。
  4. 重构。

可以发现大概是类似斜率优化那套式子,维护上凸壳即可。

注意到 \(a_i\) 始终不变,而要求的斜率不断递减,可以用单调队列维护,重构的时候也不用重新排序了。

本题还有 \(\mathcal O (n \log n)\) 的做法,在题解中同样可以看到。不过因为要手写平衡树,我比较懒就不写了。

时间复杂度为 \(\mathcal O (n \sqrt{n})\)评测链接

2020-02-18

cf627F

设初始时 \(0\)\(s\),目标时在 \(t\)

注意到操作的本质是 \(0\) 的移动,同时操作具有可逆性。

因此,我们先不考虑次数最少的要求,先让 \(0\)\(s\) 以最短距离移动到 \(t\)

如果此时已经满足目标状态了,说明不需要加入新的边,此时 \(0\) 经过的距离即为最少步数。

否则,接下来我们只能加入一条新的边,然后让 \(0\)\(t\) 出发,走到包含这条新边的环上距离 \(t\) 最近的点 \(p\),绕若干次完整的圈之后,回到 \(t\)

观察这样操作对权值的变化可以得出,\(t\)\(p\) 的路径上的所有点的权值都不会改变,同时每绕圈一次,环上除了 \(p\) 之外的点上的权值变化形成一个循环,而绕若干圈则为一个轮换

因此,权值要改变的点加上 \(p\) 应该在树上形成一条路径。

由此我们能够确定连边 \((u,v)\),可以 \(t\) 为根,找到所有权值需要改变的点,\(p\) 即为这些点中深度最小的点的父节点,而路径 \((u,v)\) 则由 \(p\) 和这些点构成。

如果深度最小的点的父节点不唯一,或者 \(p\) 和这些点无法构成一条路径,或者这些点的权值不是目标权值的一个轮换,则说明无解。

最后来考虑最小化操作次数。

对于一条加边 \((u,v)\),绕圈的方向有两种 \(u \to v\)\(v \to u\),分别计算取 \(\min\) 即可。

假设从 \(u \to v\),由这个轮换对循环的次数 \(c\) 可以得到最小次数为 \(2\cdot \operatorname{dist}(t, p) + c \cdot (\operatorname{dist}(u, v) + 1)\)

但注意这个最小次数是在先将 \(0\)\(s\) 移到 \(t\) 的前提下,因此如果有重复的路径需要减掉。

准确地说,如果是 \(u \to v\),那就是将 \(0\) 直接从 \(s\) 经过树边移动到 \(u\),然后经过新加的边移动到 \(v\),然后在这个环上再绕 \((c - 1)\) 圈回到 \(v\),最后经过树边移动到 \(t\)。此时的答案也就是 \(\operatorname{dist}(s, u) + (c - 1) \cdot (\operatorname{dist}(u, v) + 1) + \operatorname{dist}(v, t) + 1\)

如果是 \(v \to u\),只要把 \(u, v\) 互换,并重新计算循环的次数 \(c\) 即可。

时间复杂度为 \(\mathcal O (n)\)评测链接

2020-02-19

arc093_f

淘汰赛的比赛结构是一个完全二叉树,假设玩家 \(1\) 被安排在了某个位置,则他要最终获得胜利的话,需要打败 \(N\) 个对手。

\(N\) 个对手分别来自大小为 \(2^0, 2^1, 2^2, \ldots , 2^{N - 1}\) 的子树中。

也就是说,它们是那些对应的子树中的最小值。

要让 \(1\) 取得胜利,这些值中不能有那 \(M\)\(A_i\) 之一。

这相当于,把除了 \(1\) 以外的 \(2^N - 1\) 个数染上 \(N\) 种颜色,第 \(i\) 种颜色恰好要染 \(2^{i - 1}\) 个数。

而且对于每种颜色,最小的,染上这种颜色的数,不能是任何一个 \(A_i\)

然后我们考虑容斥原理,假设一个集合中的 \(A_i\) 都必须是某个颜色的最小值。

可以发现让 \(A_i\) 从大到小 DP 会比较合适。记一个状态表示比当前值大的 \(A_i\) 被强制选取了哪些颜色的最小值,也就是说哪些颜色已经被用掉了。

转移的时候,该 \(A_i\) 可以不强制选,直接转移;或者强制选成某个还未被选择的颜色 \(k\) 的最小值,DP 值乘上 \(\displaystyle \binom{s - 1}{2^{k - 1} - 1}\),其中 \(s\) 表示后面还没有被选中的数的个数,\(s\) 可以直接由当前 \(A_i\) 和选取的颜色状态计算得出。

最后答案就是容斥得到的染色方案数,乘以 \(\displaystyle 2^N \prod_{i = 1}^N (2^{i - 1})!\),这是因为每个子树内可以任意排,然后 \(1\) 每次可以从左子树或右子树上来。

时间复杂度为 \(\mathcal O (M N 2^N)\)评测链接

2020-02-20

cf506E

不考虑题目中的“在原串中插入”,我们直接统计最终的长度为 \(N = |s| + n\) 的回文串的个数。

接下来的问题是:给定一个回文串,如何判断 \(s\) 是否作为一个子序列出现。

当然可以直接子序列自动机,但是这样子的性质不够好。考虑从 \(s\) 的两侧进行匹配。

假设当前回文串为 \(t\),我们使用 \(t\) 两侧的字符对 \(s\) 两侧的字符进行匹配:
假设 \(t\) 两端的字符为 \(c\),如果 \(s\) 左端的字符也为 \(c\),就删去这个字符,右边同理。

\(s = \mathtt{abaac}, t = \mathtt{{\color{red}b}{\color{magenta}a}{\color{blue}c}{\color{Tan}b}{\color{ForestGreen}a}{\color{Tan}b}{\color{blue}c}{\color{magenta}a}{\color{red}b}}\) 为例:

  • \(\mathtt{{\color{red}b}}\) 去匹配 \(s\) 的两端,\(s\) 变为 \(\mathtt{abaac}\)
  • \(\mathtt{{\color{magenta}a}}\) 去匹配 \(s\) 的两端,\(s\) 变为 \(\mathtt{{\color{magenta}a}baac}\)
  • \(\mathtt{{\color{blue}c}}\) 去匹配 \(s\) 的两端,\(s\) 变为 \(\mathtt{{\color{magenta}a}baa{\color{blue}c}}\)
  • \(\mathtt{{\color{Tan}b}}\) 去匹配 \(s\) 的两端,\(s\) 变为 \(\mathtt{{\color{magenta}a}{\color{Tan}b}aa{\color{blue}c}}\)
  • \(\mathtt{{\color{ForestGreen}a}}\) 去匹配 \(s\) 的两端,\(s\) 变为 \(\mathtt{{\color{magenta}a}{\color{Tan}b}{\color{ForestGreen}a}a{\color{blue}c}}\)
    注意,这里只能匹配其中一个字符,因为 \(\boldsymbol{t}\) 中只剩下一个 \(\mathtt{{\color{ForestGreen}a}}\) 了!

如果 \(s\) 少一个 \(\mathtt{a}\) 或者 \(t\) 多一个 \(\mathtt{{\color{ForestGreen}a}}\),就能全部匹配。

如果按照这种方式全部匹配完了,就是合法的串。

由此我们可以构造一个 DP:\(dp(x, i, j)\) 表示确定了 \(t\) 的左右两端各 \(x\) 个字符后,恰好匹配到 \(s\) 中的子串 \(s[i : j]\)\(t\) 的方案数。
并且一个特殊的状态 \(dp(x, \mathrm{done})\) 表示匹配完了。

则答案就为 \(\displaystyle dp \!\left( \left\lceil \frac{N}{2} \right\rceil\!, \mathrm{done} \right)\)

对应的转移图如下:

但是因为 \(N\) 太大,没法直接这样做,直接做的复杂度是 \(\mathcal O ({|s|}^2 N)\) 的。

观察到这个转移图,显然就是用来矩阵快速幂的,但是还是不行,复杂度是 \(\mathcal O ({|s|}^6 \log N)\) 的。

所以还是观察一下性质,比如我们可以发现,红色点就代表 \(s\) 的两端不同的情况,绿色点表示相同的情况。

那么要到达终点,如果经过了 \(n_1\) 个红色点,就必须要经过 \(\displaystyle \left\lceil \frac{|s| - n_1}{2} \right\rceil\) 个绿色点。

然后发现终点前的点一定是绿色点,所以最多经过 \(|s| - 1\) 个红色点,也就是说经过的红色点的数量在 \(0\)\(|s| - 1\) 内。

我们单独把一条从起点到终点的链拿出来,可以发现,经过的红点和绿点的顺序实际上没有影响,也就是说把红点提前答案不变:

这个性质十分重要,因为本质不同的链的个数只有 \(\mathcal O (|s|)\) 个,所以只要求出每种链的个数就行了,同样可以使用类似的 DP 得到。

这样的话,考虑在每一条链上做矩阵快速幂,得到的答案乘以链的条数再相加就是总答案,复杂度是 \(\mathcal O ({|s|}^4 \log N)\) 的。

我们可以更进一步优化,考虑这样的自动机(字符串长度为 \(|s| = 5\) 时,也就是和刚才举的例子相同):

其中 \(g_0 \sim g_{|s| - 1}\) 分别表示经过的红点个数分别为对应值的链的个数。

可以发现恰好满足每一条本质不同的链都能够被表示出,而且不重复不遗漏。

在这个自动机上做矩阵快速幂就行了,因为加了一个空的起点,所以要多走一步。

但是这样直接求的话,对于 \(N\) 是奇数的情况会多算,就是前文提到的那种情况(最中心的字符只能匹配一个)。

我们这样考虑,先求出在 \(\displaystyle \left\lfloor \frac{N}{2} \right\rfloor\) 步内就能到达终点的方案数,乘以 \(26\)(还能再走一步)。

然后再加上在 \(\displaystyle \left\lfloor \frac{N}{2} \right\rfloor\) 步时恰好到达一开始的自动机中的 \(s\) 被删到长度为 \(1\) 时的节点的方案数。

计算第二种情况时,也要重新计算一下 \(g_0 \sim g_{|s| - 1}\),最终就能求得总答案了。

时间复杂度为 \(\mathcal O ({|s|}^3 \log N)\)评测链接

arc096_e

考虑容斥,枚举有 \(a\) 个只出现了一次,\(b\) 个一次都没出现。

则给答案贡献 \(\displaystyle {(-1)}^{a + b} \binom{n}{a} \binom{n - a}{b} 2^{2^{n - a - b}} \sum_{x = 0}^{a} {a \brace x} {(2^{n - a - b})}^x\)

如果令 \(c = a + b\),变换为 \(\displaystyle {(-1)}^c \binom{n}{c} 2^{2^{n - c}} \sum_{x = 0}^{c} {(2^{n - c})}^x \sum_{a = x}^{c} {a \brace x} \binom{c}{a}\)

考虑这个恒等式:\(\displaystyle \sum_{i = x}^{n} {i \brace x} \binom{n}{i} = {n + 1 \brace x + 1}\)

所以答案为 \(\displaystyle \sum_{c = 0}^{n} {(-1)}^c \binom{n}{c} 2^{2^{n - c}} \sum_{x = 0}^{c} {(2^{n - c})}^x {c + 1 \brace x + 1}\)

时间复杂度为 \(\mathcal O (N^2 + N \log M)\)评测链接

2020-02-21

cf575E

可以证明如下结论:

在平面直角坐标系中,给定若干个不全都共线的点。
要作一个半径尽量大的圆,使得该圆包含所有给定点,并经过至少三个给定点。
构造给定点构成的凸包,并要求凸包上不存在共线的三个顶点。由于这些点不全都共线,所以一定存在这样的凸包。
则有结论:要求的圆一定经过凸包上三个相邻顶点。

具体证明请下载 任清宇的题解 查看。

所以只要求出给出的点集的凸包后,枚举凸包上相邻三点计算并更新答案即可。

具体地说,由于每个人能够到达的点的凸包是一个点,或一个 \(3 \sim 6\) 边形,只要求出每个人对应的凸包的顶点,这可以通过简单的讨论求出,再合并求一次大凸包即可。

时间复杂度为 \(\mathcal O (n \log n)\)评测链接

cf607E

为了方便考虑,把坐标系平移到以 \((p, q)\) 为原点处。

那么以原点为圆心作圆,只要找到圆内有 \(m' < m\) 个交点的最大半径即可。

那么答案就等于圆内交点到原点的距离之和,加上 \(m - m'\) 倍的半径。

二分答案后考虑如何 check 是否有 \(< m\) 个交点。

把每个与圆有交的直线拿出来,就变成圆上的一条弦,对应了圆上极角序的一个区间。

就变成了对相交但不包含的区间对计数的问题,是二维偏序问题。

这部分时间复杂度为 \(\mathcal O (n \log n (\log v - \log \varepsilon))\)

确定了对应半径后,再使用类似方法在 \(\mathcal O (n \log n + m)\) 的时间内统计交点到原点的距离即可。

时间复杂度为 \(\mathcal O (n \log n (\log v - \log \varepsilon) + m)\)评测链接

2020-02-22

arc092_f

对于一条边 \(u \to v\),将它反向后变成 \(v \to u\),会对原图的强连通分量个数造成影响,当且仅当:

  • 忽略这条边后,\(u\) 能直接或间接到达 \(v\)
  • 忽略这条边后,\(v\) 能直接或间接到达 \(u\)

这两个条件仅恰好满足一个。证明不难,请自行脑补。

其中,忽略 \(u \to v\) 后,询问 \(v\) 是否能够到达 \(u\),和不忽略其实也没啥区别,所以这部分可以直接做,\(\mathcal O (NM)\) 的复杂度就可以接受了,当然你也可以用 bitset 做 \(\mathcal O (M + NM / w)\)

然后考虑忽略 \(u \to v\) 后,询问 \(u\) 是否能够到达 \(v\),也就是只要存在第一条边不走 \(u \to v\) 的简单路径就行。

我们考虑对于所有的起点相同,也就是 \(u\) 相同的 \(u \to v\) 计算这个东西,那么只要一次的时间复杂度为 \(\mathcal O (M)\) 就可以接受了。

首先把 \(u\) 的出边排成一排,假设终点分别为 \(v_1, v_2, \ldots , v_k\)

那么先按照正序,也就是 \(v_1, v_2, \ldots , v_k\) 的顺序进行 DFS,并记录每个点是从哪个点到达的(就是从哪个 \(v_i\) 出发),记做 \(p(v_i)\)

然后按照逆序,也就是 \(v_k, v_{k - 1}, \ldots , v_1\) 的顺序进行 DFS,并记录每个点是从哪个点到达的,记做 \(q(v_i)\)

如果一个 \(v_i\) 可以从其它 \(v_j\)\(j \ne i\))出发到达它,当且仅当 \(p(v_i) \ne q(v_i)\),只要判断这个条件即可。

时间复杂度为 \(\mathcal O (NM)\)评测链接

2020-02-23

agc023_f

第一步,必须把根节点删掉。

然后可以发现,如果删掉一个节点之后,它的孩子中有 \(0\),那就可以立刻把孩子也删掉,这样答案不会变得更劣。

那我们把 \(0\) 和它的父亲并成一个连通块,表示这个连通块可以一次性取完,最后整棵树就变成了一些不相交连通块。

然后会发现,如果此时我们把每个连通块看成一个节点,还是一棵树的结构,但是这时每个连通块内就有若干个 \(0\)\(1\) 混合了。

现在仅考虑新树的两个节点 \(u, v\),忽略其它的影响:

假设 \(x\)\(0, 1\) 的个数分别为 \(x_0, x_1\),则如果 \(u\) 排在 \(v\) 前面,就会增加 \(u_1 v_0\) 对逆序对,反之增加 \(v_1 u_0\) 对。

如果 \(u_1 v_0 < v_1 u_0\),则 \(u\) 排在 \(v\) 前面肯定更优。

变换一下式子,变成 \(\displaystyle \frac{u_1}{u_0} < \frac{v_1}{v_0}\),也就是连通块中 \(1\)\(0\) 个数的比值。

考虑当前这个比值最小的连通块,假设为 \(a\),则可以发现当 \(a\) 的父亲被取到的时候,下一步一定会把 \(a\) 取了。

这是因为无论连通块怎么合并,这个比值都不会变得比原来更小,也就不会小于 \(a\) 的比值。

所以,拿一个支持插入删除,取出最小值的数据结构(比如 set),就可以维护了。

具体地说就是每次取出这个比值最小的连通块,把它的它的父亲合并。

时间复杂度为 \(\mathcal O (n \log n)\)评测链接

2020-02-25

agc038_f

\(P\) 分解成不相交循环的乘积后,考虑其中一个循环 \((a_1, a_2, \ldots , a_k)\)

不失一般性,可以把这个循环看作 \((1, 2, \ldots , k)\)

那么对于 \(A_1\),有两种情况:\(A_1 = 1\)\(A_1 = P_1 = 2\)

如果 \(A_1 = 1\),则考虑 \(A_k\) 有两种情况:\(A_k = k\)\(A_k = P_k = 1\),但是因为 \(A_1 = 1\),所以只能有 \(A_k = k\)
以此类推,可以得到:对于这个循环中的所有元素 \(i\),均有 \(A_i = i\)

如果 \(A_1 = 2\),则考虑 \(A_2\) 有两种情况:\(A_2 = 2\)\(A_2 = P_2 = 3\),但是因为 \(A_1 = 2\),所以只能有 \(A_2 = 3\)
以此类推,可以得到:对于这个循环中的所有元素 \(i\),均有 \(A_i = P_i\)

换句话说,对于每个循环,要么这个循环被完全保留,要么这个循环被完全拆解成一个个自环。

上述结论对 \(Q\)\(B\) 当然也适用。

我们称选择一个循环,指这个循环被完全保留,称不选一个循环,指这个循环被拆解成了一个个自环。

接着,考虑一个 \(P\) 中的循环 \(a\) 和一个 \(Q\) 中的循环 \(b\),假设它们共有一个元素 \(i\)。分若干类讨论:

  1. \(P_i = Q_i = i\):无论如何,这个位置上均有 \(A_i = B_i\)
  2. \(P_i = i, Q_i \ne i\):如果选择\(b\),则这个位置上有 \(A_i \ne B_i\),否则不选 \(b\),则这个位置上有 \(A_i = B_i\)
  3. \(P_i \ne i, Q_i = i\):如果选择\(a\),则这个位置上有 \(A_i \ne B_i\),否则不选 \(a\),则这个位置上有 \(A_i = B_i\)
  4. \(P_i \ne i, Q_i \ne i, P_i \ne Q_i\):如果不选 \(a\)不选 \(b\),则这个位置上有 \(A_i = B_i\),否则这个位置上有 \(A_i \ne B_i\)
  5. \(P_i \ne i, Q_i \ne i, P_i = Q_i\):如果 \(a, b\) 同时选择或同时不选,则这个位置上有 \(A_i = B_i\),否则这个位置上有 \(A_i \ne B_i\)

最终需要最大化 \(A_i \ne B_i\) 的下标 \(i\) 的数量,也就是最小化 \(A_i = B_i\) 的下标 \(i\) 的数量。

如果在上述 \(5\) 种情况中,一旦发生了 \(A_i = B_i\),就赋有 \(1\)代价,那么就是要最小化总代价。

可以发现类似于一个文理分科模型,可以建立一个网络流模型,求最小割得到答案。

但是因为有些条件不符合,没法直接套用。

不过,如果把 \(Q\) 中的循环割掉与源点和汇点之间的边的意义交换,就可以套用了。

而且可以发现,这样建出来的图是一个二分图,因为 \(P\) 中的循环只和源点连边,\(Q\) 中的循环只和汇点连边,\(P, Q\) 之间也只会互相连边。(如果 \(P\) 中的循环对应的节点,割掉与源点相连的边的意义是不选它,而 \(Q\) 中的循环对应的节点的意义恰好相反的话)

所以最终是在单位容量的二分图上求最小割,使用 Dinic 算法可以做到 \(\mathcal O (|E| \sqrt{|V|})\) 的复杂度。

时间复杂度为 \(\mathcal O (N \sqrt{N})\)评测链接

agc023_d

如果 \(X_1 < S < X_N\),考虑第 \(1\) 栋楼和第 \(N\) 栋楼。

如果 \(P_1 \ge P_N\),即第 \(1\) 栋楼中的人数大于等于第 \(N\) 栋楼中的人数,则班车一定会先去第 \(1\) 栋楼。证明:

  • 如果 \(N = 2\),显然成立。
  • 如果 \(N \ge 3\)\(X_{N - 1} < S\),显然除了第 \(N\) 栋楼的员工,都希望前往负方向,所以一定会前往负方向。
  • 如果 \(N \ge 3\)\(S < X_{N - 1}\),如果在到达第 \(1\) 栋楼之前没有到达第 \(N - 1\) 栋楼,则结论成立,否则转化为前两种情况。

所以说不管怎么样都会先前往第 \(1\) 栋楼,然后就可以一路向右径直跑到第 \(N\) 栋楼。

这就意味着,第 \(N\) 栋楼中内的员工的回家时间,一定等于第 \(1\) 栋楼的回家时间,加上 \(X_N - X_1\)

也就是说,第 \(N\) 栋楼中的员工,其实是和第 \(1\) 栋楼中的员工站在同一条线上的。第 \(1\) 栋楼的员工想投什么票,他们也一定会跟着投。所以说这第 \(N\) 栋楼的员工其实和第 \(1\) 栋楼的员工没什么区别,暂时(在第 \(1\) 栋楼的员工回家之前)让他们搬家到第 \(1\) 栋楼也对运行路径没有影响。

所以说,如果让 \(P_1 \gets P_1 + P_N\),然后删去第 \(N\) 栋楼,计算这种情况下的到达第 \(1\) 栋楼的时间,加上 \(X_N - X_1\) 就是答案。

如果 \(P_1 < P_N\),那么以上结论的方向反过来即可。

这样递归下去,直到不满足 \(X_1 < S < X_N\) 为止,那样的话就可以直接计算答案了。

时间复杂度 \(\mathcal O (N)\)评测链接

2020-02-26

agc036_d

考虑差分约束模型,图中不存在负环等价于存在一组合法的差分约束的解。

考虑每个节点作为一个变量,第 \(i\) 个节点对应的变量为 \(x_i\)

因为初始的边不能删去,所以一定有 \(x_i \ge x_{i + 1}\)

考虑令 \(q_i = x_i - x_{i + 1}\),那么就会有 \(q_i \ge 0\)

假设保留了一条边权为 \(-1\)\(i \to j\) 的边,也就是说 \(i < j\) 的话:
就会有 \(x_i - 1 \ge x_j\),即 \(x_i - x_j \ge 1\),也就是说 \(q_i + q_{i + 1} + \cdots + q_{j - 1} \ge 1\)

假设保留了一条边权为 \(1\)\(i \to j\) 的边,也就是说 \(i > j\) 的话:
就会有 \(x_i + 1 \ge x_j\),即 \(x_j - x_i \le 1\),也就是说 \(q_j + q_{j + 1} + \cdots + q_{i - 1} \le 1\)

反过来想,如果确定了所有的 \(q_i\),那么每一条边就应该尽可能地保留下来,这样代价最小。

对于边权为 \(-1\) 的边,是区间和 \(\ge 1\) 才能保留,也就是说如果区间和 \(= 0\) 就必须删除。

对于边权为 \(1\) 的边,是区间和 \(\le 1\) 才能保留,也就是说如果区间和 \(\ge 2\) 就必须删除。

也就是说,对于一种 \(q\) 的取值方案,\(q_i = 0\) 的每个连续段,都对应着一系列的边权为 \(-1\) 的边的删除。

而区间和 \(\ge 2\) 的区间也对应着边权为 \(1\) 的边的删除。

显然可以发现,如果出现了 \(q_i \ge 2\),不如把它变成 \(1\),这样一定会变得更优(边 \(i \to (i + 1)\) 不用被删除了)。

所以只需要考虑 \(q\) 的取值为 \(\{0, 1\}\) 的情况。

然后可以发现,每个 \(0\) 的连续段就对应着一部分区间的删除,所以考虑如下 DP:

\(dp(i, j)\) 表示考虑到了 \(q_i\),最后一个 \(1\) 取在了 \(q_i\),倒数第二个 \(1\) 取在了 \(q_j\) 处的情况下,可以确定的代价的最小值。

\(dp(i, j)\) 可以从 \(dp(j, k)\) 转移而来,利用二维前缀和可以快速求出转移系数。

时间复杂度为 \(\mathcal O (N^3)\)评测链接

2020-02-27

agc026_e

\(a_i\) 表示第 \(i\)\(\mathtt{a}\) 的位置,\(b_i\) 表示第 \(i\)\(\mathtt{b}\) 的位置。

考虑如何比较两个字符串的字典序,可以发现当某个前缀相同时应该比较后缀,所以考虑从后往前 DP:

\(dp(i)\) 表示只考虑所有的 \(a_{i \sim N}\)\(b_{i \sim N}\),也就是第 \(i\) 对以及之后的 \(\mathtt{a}, \mathtt{b}\) 的情况下的字典序最大的串。

注意不是\(i\)\(\mathtt{a}, \mathtt{b}\) 以及它们之后的所有字符都一定选择,而是一对一对的选择的。

那么答案就为 \(dp(1)\)。而 \(dp(i)\) 可以从两个方向转移,也就是 \(a_i\)\(b_i\) 保留或者删掉。

如果删掉,就直接从 \(dp(i + 1)\) 转移而来。

否则考虑如果保留第 \(i\)\(\mathtt{a}, \mathtt{b}\) 的话会怎么样,根据先后顺序分成两类讨论:

  1. \(a_i < b_i\):也就是形如 \(\cdots \mathtt{{\color{red}a}{\color{blue}a}{\color{green}b}{\color{blue}a}{\color{blue}a}{\color{green}b}{\color{red}b}} \cdots\) 的情况。
    红色的字符就是第 \(i\)\(\mathtt{a}, \mathtt{b}\)绿色的字符表示第 \(i\) 对之前的字符,蓝色的字符表示第 \(i\) 对之后的字符。
    注意绿色的字符只可能是 \(\mathtt{b}\),而蓝色的字符只可能是 \(\mathtt{a}\)。因为绿色的字符不会被保留,之后忽略它们。
    既然已经确定了必须选取 \(a_i, b_i\),因为要让字典序尽量大,所以 \(a_i\)\(b_i\) 之间所有的 \(\mathtt{a}\) 都应该被删掉。
    也就是说,\(dp(i)\) 就应该等于 \(\mathtt{ab} + dp(k)\),其中 \(k\) 为完全在 \(b_i\) 之后的第一对 \(a_k, b_k\) 的编号。
  2. \(a_i > b_i\):也就是形如 \(\cdots \mathtt{{\color{red}b}{\color{blue}b}{\color{green}a}{\color{blue}b}{\color{blue}b}{\color{green}a}{\color{red}a}} \cdots\) 的情况。
    红色的字符就是第 \(i\)\(\mathtt{a}, \mathtt{b}\)绿色的字符表示第 \(i\) 对之前的字符,蓝色的字符表示第 \(i\) 对之后的字符。
    注意绿色的字符只可能是 \(\mathtt{a}\),而蓝色的字符只可能是 \(\mathtt{b}\)。因为绿色的字符不会被保留,之后忽略它们。
    既然已经确定了必须选取 \(a_i, b_i\),因为要让字典序尽量大,所以 \(a_i\)\(b_i\) 之间所有的 \(\mathtt{b}\) 都应该被保留。
    而确定要保留这些 \(\mathtt{b}\),又会导致往后包含了更多的 \(\mathtt{b}\),同理被包含的 \(\mathtt{b}\) 也应该被保留,连锁反应会一直进行下去,直到某一次不包含了更多的 \(\mathtt{b}\) 为止。举个例子:
    考虑 \(\mathtt{{\color{blue}b}b{\color{blue}a}babbbabaaaabbabaaaabb}\)
    选取 \(\mathtt{{\color{red}b}{\color{blue}b}{\color{red}a}b{\color{blue}a}bbbabaaaabbabaaaabb}\)
    选取 \(\mathtt{{\color{red}{bba}}{\color{blue}b}{\color{red}a}bbb{\color{blue}a}baaaabbabaaaabb}\)
    选取 \(\mathtt{{\color{red}{bbaba}}{\color{blue}{bbb}}{\color{red}a}b{\color{blue}{aaa}}abbabaaaabb}\)
    选取 \(\mathtt{{\color{red}{bbababbba}}{\color{blue}b}{\color{red}{aaa}}{\color{blue}a}bbabaaaabb}\)
    选取 \(\mathtt{{\color{red}{bbababbbabaaaa}}bbabaaaabb}\)
    在这种情况下,\(dp(i) = \mathtt{bbababbbabaaaa} + dp(k)\),其中 \(k\) 为后面部分的第一对 \(a_k, b_k\) 的编号。

所以只要求出以上两类的结果就行,第 1 类可以预处理,第 2 类的开头的字符串,可以直接扫一遍判断。

时间复杂度为 \(\mathcal O (N^2)\)评测链接

cf679E

注意到在可能的值域(约为 \({10}^{14}\))内,\(42\) 的次幂并不多,尝试从这个角度考虑。

操作 3 比较棘手,解决的办法是用线段树维护当前值到下一个 \(42\) 的次幂的差值。

做操作时让这个差值做区间减法,在线段树递归的时候,如果差值会变成负数,就需要再递归进子区间进行修改,但是如果这个区间被打上了区间覆盖标记,就直接修改这个标记就行。

执行完后,如果存在差值为 \(0\) 的位置,就再执行一次。

这个做法的复杂度,使用势能函数可以分析得出为 \(\mathcal O (q \log n \log_{42} v)\)

具体地说,令当前线段树的势能函数等于每个值相同的连续段,比此连续段的值大的,在值域内的 \(42\) 的次幂的个数的总和,乘以 \(\log n\)

则操作 2 和操作 3 的摊还代价都为 \(\mathcal O (\log n \log_{42} v)\)

时间复杂度为 \(\mathcal O ((n + q) \log n \log_{42} v)\),其中 \(v\) 为值域,约为 \({10}^9 q\)评测链接

2020-02-28

agc039_e

\(n = 2 N\),枚举第 \(n\) 个点和哪个点连了,假设为 \(k\),即:

就分成了 \(1 \sim (k - 1)\)\((k + 1) \sim (n - 1)\) 两段。

直接考虑如果是区间 \([i, j]\),且这区间中的一点 \(k\) 与区间外的一点连线了,即:

如果 \(i < j\),那么被 \(k\) 分割的左右两边必然要通过至少一条线与 \((? \leftrightarrow k)\) 连接起来

但是又不能交叉,如果交叉就形成环了,所以取最上方的一条线 \((x \leftrightarrow y)\)

所谓最上方,形式化地说就是 \(x\) 最靠近 \(i\)\(y\) 最靠近 \(j\)

那么,\(x, y\) 在两边必然就会有各自的“管辖范围”。
(你可以理解成,从 \((? \leftrightarrow k)\)\((x \leftrightarrow y)\) 的交点出发向 \(x\)\(y\) 方向走,能遍历到的区域,它和其它区域不相交)

假设这个范围分别为 \([i, p]\)\([q, j]\)

那么如果我们枚举 \(i, j, k, x, y, p, q\)(满足 \(i \le x \le p < k < q \le y \le j\)):

就可以转化成三个子问题 \([i, p](x)\)\([p + 1, q - 1](k)\)\([q, j](y)\)

可以在 \(\mathcal O (n^7)\) 的复杂度内解决此问题,因为常数大约是 \(1 / 7! = 1 / 5040\),所以其实是可以过的。


不过可以继续优化,可以发现 \([i, p]\)\([q, j]\) 是和 \(k\) 独立的,也就是如果 \([i, j]\) 固定,\(k\) 的位置不影响 \(p, q\) 的选择。

那么我们考虑先枚举 \(p, q\),得到 \([i, p] \circ [q, j]\) 这个子问题,再在子问题里枚举 \(x, y\)

则处理所有 \([i, q] \circ [q, j]\) 就可以做到 \(\mathcal O (n^6)\) 的复杂度(枚举 \(6\) 个变量)。

外层的 \([i, j](k)\) 就可以只枚举 \(p, q\) 进行转移,这部分复杂度为 \(\mathcal O (n^5)\)

总时间复杂度为 \(\mathcal O (n^6)\),同样带了一个 \(1 / 6! = 1 / 720\) 的常数。


不过可以继续优化,现在复杂度瓶颈是在 \([i, p] \circ [q, j]\) 这里,需要枚举 \(x, y\) 才能转移。

如果只枚举一个 \(y\) 呢?

那就需要求 \([i, p]\) 区间中的,从 \(y > p\) 连进来一条边的方案数,用记号 \([i, p]\{y\}\) 表示。

当然还有本来就要求的 \([q, j](y)\),这个是旧的东西了。

那么考虑计算 \([i, p]\{y\}\),这时就可以枚举具体是和哪个 \(i \le x \le p\) 连边,然后直接加上 \([i, p](x)\) 即可。

所以处理所有 \([i, p]\{y\}\) 的复杂度为 \(\mathcal O (n^4)\),而处理所有 \([i, p] \circ [q, j]\) 的复杂度降为 \(\mathcal O (n^5)\)

总时间复杂度为 \(\mathcal O (n^5)\),带了一个 \(1 / 5! = 1 / 120\) 的常数,评测链接

posted @ 2020-03-01 16:26  粉兔  阅读(2703)  评论(5编辑  收藏  举报