IOI 2020 集训队作业胡扯「1, 50」

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

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


agc037_e

本题是在获得集训队训练资料前就已经做过的,故写在开头。

\(S\) 中的最小字符为 \(c\),考虑最终得到的串,其开头的连续 \(c\) 的长度必然要最大化。

考虑最初始的 \(U = ST\)\(U\) 中的最长连续 \(c\) 可以放在新的 \(S\) 的开头或末尾,如果此次操作是最后一次,则放在开头,否则放在末尾。假设初始的 \(U\) 的最长 \(c\) 连续段长度为 \(L\),这样一来可以在最终串里构造出长度为 \(\min \{ N, 2^{K-1} L \}\)\(c\) 的连续段。

当连续段长度确定时,再比较之后的字符串的字典序,稍加推导可以发现其实就是初始的 \(U\) 的一个后缀,因为 \(n\) 不大,暴力比较即可。

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

agc029_c

本题是在获得集训队训练资料前就已经做过的,故写在开头。

先特判答案为 \(1\) 的情况,然后二分答案 \(m\),其实就是在 \(m\) 进制下找递增数列,考虑到非 \(0\) 的位置很少,随便用个 map 或者数组维护一下就行。

之前写的是用 map 的,重制版用的是数组。

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

agc025_d

本题是在获得集训队训练资料前就已经做过的,故写在开头。

我们可以证明,在所有距离恰好为 \(\sqrt{D}\) 的格点对之间连边,形成的图必然是一个二分图。

\(D\) 为奇数时,对格点进行黑白染色然后考虑 \([{(\Delta x)}^2 + {(\Delta y)}^2]\) 为奇数即可得证。
\(D\) 为偶数时,正好相反,黑色点之间会相互连边(白色点同理),将坐标缩小至原来的 \(1 / \sqrt{2}\) 倍,等价于 \(D / 2\) 的情况进行归纳。

\([0, 2 N) \times [0, 2 N)\) 中的所有格点进行关于 \(D_1\) 的黑白染色,和关于 \(D_2\) 的红蓝染色。

选取四种颜色搭配中较多的那一种,根据抽屉原理至少有 \(N^2\) 个点。

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

2019-10-30

cf516D

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

cf506C

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

2019-10-31

cf555E

容易看出给一张无向图定向后可以变成强连通图当且仅当这张图是一张边双连通图。

将每个边双连通分量缩成一个点,在形成的森林上用类似 Tarjan LCA 的方法判断是否合法。

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

cf576D

按照需要的次数从小到大考虑每个航班,矩阵快速幂优化转移,bitset 优化矩乘。

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

2019-11-06

cf512D

先对图做一个类似拓扑排序 / BFS 的算法,将图拆成若干无根树和有根树(样例解释的图片写得很清楚),对于每棵树分别做背包合并即可。

对于有根树的背包是显然的,用 \(f(u, i)\) 表示在 \(u\) 的子树中删去 \(i\) 个点的方案数,转移是显然的树上背包形式。

对于无根树,对所有点为根都做一次 DP,考虑所有 DP 值的总和,删去了 \(i\) 个点的方案数会被重复统计 \(\mathrm{siz} - i\) 次(\(\mathrm{siz}\) 是这棵无根树的大小,\(0 \le i < \mathrm{siz}\)),所以 \(f(\ast, i)\) 除以 \(\mathrm{siz} - i\) 即可。

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

2019-11-08

cf575A

矩阵快速幂 sb 题,有个地方没开 long long 一直 TLE7。

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

cf547E

本着能用 ACAM 不用 SA,能用 SA 不用 SAM 的指导思想,这题就是 AC 自动机 fail 树上 DFS 序建树状数组裸题了。

时间复杂度为 \(\mathcal O (|\mathbf{\Sigma}| l + (q + l) \log l)\),其中 \(\displaystyle l = \sum |s_i|\)评测链接

cf704B

首先把绝对值拆开,把 \(x_i\) 取或正或负,加到 \(a_i, b_i, c_i, d_i\) 上,就可以把边的代价转移到端点上,然后只需考虑每个点进出的方向。

考虑最终的某个完整的路径,只看前 \(i\)\(1 \le i < n\))个点的话,会被拆成若干条链,有的链可能包含起点或终点(不能同时包含)。
\(f(i, j)\) 表示前 \(i\) 个点,有 \(j\) 条链(不算包含起点或终点的链)时的最小代价(只统计前 \(i\) 个点的代价)。
\(i + 1\) 个点的转移就是合并两条链,延伸一条链,或者自成一条链,对于包含起点或终点的链特殊处理一下即可。

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

2019-11-09

cf528C

一张连通无向图能给每条边定向满足每个点的入度出度均为偶数当且仅当这张图存在欧拉回路且边数为偶数。证明不会,看题解的。

所以先添加边把奇点两两配对,如果边数还是奇数,就再加个自环。然后求欧拉回路,路径上的边方向交替定向即可。

这题题面上没说保证原图是连通图,但是确实是连通的,我也没话说……

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

2019-11-10

cf685C

很显然可以二分答案,然后把每个曼哈顿距离拆成 \(8\) 个不等式交一下,然后取一个交出的格点即可。

但是,草了,就是解不出来不等式,就是 WA6 了,我有什么办法?不得不看题解代码 /cy

时间复杂度为 \(\mathcal O (n \log v)\),其中 \(v\) 是值域,评测链接

cf704C

题目要求的是使得形如 \((x_a \vee \overline{x_b}) \oplus (\overline{x_c}) \oplus \cdots \oplus (x_d \vee \overline{x_d}) \oplus (x_e \vee x_f)\) 的布尔表达式的取值为 \(1\) 的变量赋值方案数。
满足每个子句 \(\cdots \oplus (x_i \vee x_j) \oplus \cdots\) 仅有 \(1\)\(2\) 个变量,且每个变量在表达式内最多出现两次(\(x_i\)\(\overline{x_i}\) 的形式均算一次)。

\(m\) 个变量抽象为 \(m\) 个节点,把每个形如 \((x_i \vee x_j)\)(或换成 \(\overline{x_i}\)\(\overline{x_j}\))的表达式看作一条连接 \(x_i\)\(x_j\) 的边。
则有每个节点的度数最多为 \(2\),也就是说整个图形成了若干个连通块,每个连通块要么是链要么是环。

如果连通块是链,从链的一端递推转移,记状态为当前考虑的变量的取值为 \(0\)\(1\) 时,整体表达式为 \(0\)\(1\) 的取值方案数,每个连通块转移完后并入总答案。需要注意的是链的两端(假设为 \(x_i\))可能有形如 \((x_i)\)\((\overline{x_i})\) 的表达式,需要特殊处理。

如果连通块是环,类似地从环上某个点以某个方向递推,状态表示要多起始点的取值为 \(0\)\(1\) 这一维,转移与链类似,每个连通块转移完后并入总答案。比链的情况方便的是,环上不可能出现形如 \((x_i)\)\((\overline{x_i})\) 的表达式了。

孤立点,或者只有 \((x_i)\)\((\overline{x_i})\) 的节点需要特殊处理。

特别地,如果出现了 \((x_i \vee x_i)\)(或 \(\overline{x_i}\))也需要特殊处理,且该变量 \(x_i\) 不会出现在其它表达式中。

想着好像很简单,但是越写越麻,有点自闭。

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

2019-11-11

cf536D

先用 Dijkstra 求出 \(s\)\(t\) 到每个点的距离,离散化后值域为 \(\mathcal O (n)\)

把每个点 \(i\) 表示为平面上的点 \((\operatorname{dis}(s, i), \operatorname{dis}(t, i))\),权值为 \(p_i\)

转化为有两根线,初始时分别在 \(x\) 轴和 \(y\) 轴上,先手操作水平线,后手操作垂直线,每次将线往上 / 右移动且至少经过一个点,获得经过的点的权值,两人均最大化自己的收益,问最终两人的收益。

这是显然的零和博弈,因为坐标范围不大,直接 DP 就做完了,就是要用一个后缀 \(\min\) 优化。

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

2019-11-12

cf674D

感谢出题人保证了没有长度小于等于 \(2\) 的环,要不然人就没了。

假设图是一棵树,那么有一个常见的套路是修改时只考虑孩子对双亲产生的影响,询问时加上双亲对自己的影响即可,这样每次只会改 \(\mathcal O (1)\) 的信息,这里是基环树也没什么影响。

这里要实现一个全局极值查询的操作,考虑到对孩子的修改会导致双亲的度数变化从而导致双亲的其它子节点(兄弟节点)的权值变化,无法直接维护。不过这个变化量是相等的,即双亲节点的度数变化对不同孩子节点的贡献产生相同的变化。可以考虑对于每个节点维护一个它所有子节点的权值(不算它对子节点的影响)的集合,当子节点权值发生变化或自身度数发生变化时重新维护集合并更新对总答案的贡献(每个集合只需要贡献出其最大最小值即可)。

可以发现这样处理的话,每次改动的集合数量就是 \(\mathcal O (1)\) 的:假设修改的点为 \(i\),将 \(f(i)\) 改为 \(j\),权值(不考虑双亲对孩子的影响)有变化的有 \(f(i)\)(因为 \(i\) 不再是它的子节点了,而且度数变化了),\(f(f(i))\)(因为 \(f(i)\) 的度数变化了,对它的贡献变化了),\(j\)(理由同 \(f(i)\)),\(f(j)\)(理由同 \(f(f(i))\))。它们的权值变化会影响它们的双亲节点维护的集合的变化,所以还要更新一些集合。

总共有 \(6\) 个要更新的点,其中还有重复的,写起来比较复杂,先假设 \(i\) 被删除了,更新 \(f(i)\)\(f(f(i))\)\(f(f(f(i)))\),然后再更新 \(j\)\(f(j)\)\(f(f(j))\) 会好考虑些。

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

2019-11-13 ~ 2019-11-19

CSP 缓冲周。

2019-11-20

cf568E

怎么看这个 \(k \le 1000\) 都不好用,只能是 \(\mathcal O (k(n + m))\) 了吧,据说 CF 评测机一秒十亿,那我两亿跑 1.5s 应该能过吧(
瞄了一眼题解发现确实是,那就放心了。

考虑求最长上升子序列的二分的做法,即维护 \(f_i\) 表示要达到长度为 \(i\) 的上升子序列,序列的最后一个元素最小可以是多少,如果达不到则为 \(\infty\)。每次考虑新元素 \(a\) 的时候将 \(f_x\) 改为 \(a\) 即可,其中 \(x\) 是满足 \(f_{x} \ge a\) 的最小的 \(x\),可以二分查找求出。

遇到空位的时候,因为是严格上升子序列,可以发现不需要考虑重复元素等情况,即可以当作无限制地使用给出的数,最后还原方案时再考虑构造即可。

还原方案时从后往前维护,令当前位置为 \(i\),对于有空位的位置不好考虑(因为有 \(m\) 种取值无法一一考虑),所以考虑枚举上一个不是空位的位置 \(j\),需要满足中间的可以填进空位的最多个数恰好为两个位置 \(i\)\(j\) 的最长上升子序列之差(\(num = len_i - len_j - 1\)),然后按照数值从大到小的顺序将 \(num\) 个数填入从后往前的每个空位即可。

最后再随意填入还没填入数值的空位就行了。

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

2019-11-21

cf671D

\(1\) 为根建树。

如上图,\(u\) 是非根节点,\(p\)\(u\) 的双亲节点,令 \(f_u\) 表示覆盖图上的子树的最小代价,即覆盖 \(u\)\(p\) 之间的边以及 \(u\) 的子树中的所有边的代价。

则最终的答案为 \(1\) 的每个孩子的 \(f\) 值之和。

如上图,这种方法的好处在于:假设考虑使用了红色线覆盖了 \(u \leftrightarrow p\) 这条边,则贡献为图中的蓝色数值 + 红色线的代价。

如上图,考虑一条形如红色线的覆盖链,即经过 \(u\)\(u\) 的孩子 \(a\) 的链,考虑从 \(a\) 继承转移信息。

可以发现,假设红色链对 \(f_a\) 的贡献为 \(v\),则对 \(u\) 的贡献应该为 \(\displaystyle v + \sum_{\begin{subarray}{c} x \in {son}_u \\ x \ne a \end{subarray}} f_x\),即 \(\displaystyle v + \sum_{x \in {son}_u} f_x - f_a\)

所以考虑直接从子树继承贡献,但是经过 \(u \leftrightarrow a\) 的红色线可能不会经过 \(u \leftrightarrow p\),所以维护一个所有转移的可并堆,堆为按照转移代价为权值的小根堆,当堆顶不合法时弹出堆顶即可。

可并堆需要维护整体打加减标记(\(\displaystyle v + \sum_{x \in son_u} f_x - f_a\))以及合并,手写左偏树实现即可。

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

2019-11-22

agc033_d

考虑一个朴素的 DP:\(dp(topleft, bottomright)\) 表示左上角为 \(topleft\),右下角为 \(bottomright\) 时这个矩形区域的权值。

状态数就是 \(\mathcal O (H^2 W^2)\) 的了,考虑优化状态。

容易发现权值最大不超过 \(\lceil \log_2 H \rceil + \lceil \log_2 W \rceil\),且在当 \((i + j) \bmod 2 = 0\)\(A_{ij}\).否则为#,即黑白染色时取到上限。

那么记 \(f(complexity, top, bottom, left)\) 为满足 \(dp(topleft, bottomright) \le complexity\) 的最大的 \(right\) 值,如果不存在这样的 \(right\) 则为 \(left - 1\)

同理记 \(g(complexity, left, right, top)\) 为满足 \(dp(topleft, bottomright) \le complexity\) 的最大的 \(bottom\) 值,如果不存在这样的 \(bottom\) 则为 \(top - 1\)

这样子就可以实现转移,具体方式是:以 \(complexity\) 为阶段,每次从上一个阶段转移而来(可以滚动数组)。
先考虑 \(f\) 只算劈成左右两半的方案的贡献,\(g\) 只算劈成上下两半的方案的贡献,这样子可以直接以 \(f(top, bottom, left) = f'(top, bottom, f'(top, bottom, left) + 1)\) 的方式进行转移。\(g\) 同理,最后再固定 \(topleft\),利用双指针进行合并即可。

时间复杂度为 \(\mathcal O (W H (W + H) \log WH)\)评测链接

2019-11-23

cf605E

假设已经求出了所有点到终点 \(n\) 的距离,则每个点必然会前往距离尽量小的点,列出满足条件的方程,以 Dijkstra 的方式从终点 \(n\) 往回逆推即可。

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

cf585E

\(\displaystyle v = \max_{i = 1}^{n} a_i\),以及 \(\displaystyle b_x = \sum_{i = 1}^{n} [a_i = x]\),即 \(b_x\)\(x\)\(a\) 中出现的次数。

利用 \(b\) 数组求出 \(b'\) 数组,满足 \(b'_x\)\(x\) 的倍数在 \(a\) 中出现的次数。
具体的求法为:枚举质数 \(p\) 做该维时间复杂度为 \(\displaystyle \mathcal O \!\left( \frac{n}{p} \right)\) 的高维后缀和,即做一个类似 FMT 的变换。
由于 \(\displaystyle \sum_{\begin{subarray}{c} p \in \mathbb{P} \\ p \le n \end{subarray}} \frac{1}{p} = \mathcal O (\log \log n)\),所以这部分的时间复杂度为 \(\mathcal O (v \log \log v)\)

求出 \(b'\) 后,就可以求出 \(f\) 表示从 \(a\) 中选出一个非空子集满足 \(\gcd = 1\) 的选择方案数。
以及 \(g\) 表示从 \(a\) 中选出一个非空子集满足 \(\gcd = 1\) 的子集大小的和。
\(\displaystyle f = \sum_{\gcd(S) = 1} 1\),以及 \(\displaystyle g = \sum_{\gcd(S) = 1} |S|\)
\(f\)\(g\) 都可以通过简单的莫比乌斯反演求出。

通过容斥原理不难得出答案即为 \(2g - nf\)

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

2019-11-26

cf521E

不难发现答案中的三条路径必定在同一个点双中,进一步地,这个点双中的边数必须大于点数(不是环)。
也就是说只要原图不是仙人掌森林就必然能找到方案。

对于一个边数大于点数的点双,考虑其中的一个环,这个环上必然有一条“弦”,即一条链连接着环上的两点,则将起点和终点设为这条“弦”的两端,三条路径分别为“弦”和环被“弦”分成的两半即可。具体实现细节详见代码。

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

2019-11-27

cf521D

对于三种不同的操作,易证:赋值操作最先执行;加法操作其次;乘法操作最后执行。

考虑最终价值是所有技能价值的乘积,所以乘法操作对最终价值产生 \(b_j\) 倍的贡献,按照 \(b_j\) 从大到小的顺序排序。

对于赋值操作,每个技能只要留下最大的那个即可,可以发现此时赋值操作和加法操作可以视作同一种,即把赋值操作的 \(b_j\) 减去 \(a_{i_j}\) 即可,最终如果选取了这个赋值操作就把它提到最前面去,不影响答案。

对于加法操作,显然同一个技能的加法操作应该先选择 \(b_j\) 大的。由这个前提不难推出,每次应该选择 \(\dfrac{b_j}{a_{i_j}}\) 最大的操作执行(\(a_{i_j}\)当前的技能价值,而不是初始价值)。按照 \(\dfrac{b_j}{a_{i_j}}\)\(a_{i_j}\) 对相同的 \(i_j\) 也不一定相同)从大到小排序即可。

假设最终选取了 \(x\) 个加法操作,易证答案以 \(x\) 为自变量的时候是单峰的,只要让 \(x\)\(0\) 开始增加,直到答案无法增大时停下即可。

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

cf547D

构造二分图,左侧的点表示每一行,右侧的点表示每一列。第 \(x\) 行表示的点和第 \(y\) 列表示的点之间有连边当且仅当坐标 \((x, y)\) 在输入中给出。

cf528C 相同的结论,利用边数为偶数的欧拉回路构造方案。

特别地,这张图还是二分图,每一侧新建一个虚点,左侧的度数为奇数的点和右侧的虚点连边,右侧反之。如果最后虚点度数为奇数,则在两虚点间连一条边。因为如果一张连通二分图存在欧拉回路,则其边数必然为偶数,就不用添加自环了(自环会影响答案合法性)。

构造出边数为偶数的欧拉回路后,欧拉回路上的边交替用红蓝两色染色,可以保证不包含新的边时,每个点相邻的边中的颜色平衡。因为每个实点最多往外连一条边,所以去掉一条边后颜色差不超过 \(1\)

时间复杂度为 \(\mathcal O (n + v)\),其中 \(v\) 为值域,评测链接

2019-11-29

cf582D

\(v_p(n)\)\(p\) 是质数,\(n\) 是正整数)表示 \(n\) 的标准分解式中的 \(p\) 的幂次。

可以发现 \(\displaystyle v_p \!\left( \binom{a + b}{a} \right) = v_p( (a + b)! ) - v_p(a!) - v_p(b!)\)

\(a, b\) 表示为 \(p\) 进制数后,不难发现,在 \(p\) 进制下进行 \(a\)\(b\) 的加法运算时,进位的次数恰好等于 \(\displaystyle v_p \!\left( \binom{a + b}{a} \right)\)

所以将 \(A\) 转为 \(p\) 进制数(朴素实现的时间复杂度为 \(\mathcal O (\log A \cdot \log_p A)\))后进行数位 DP 即可。

\(f(i, j, 0/1, 0/1)\) 表示当位数从高到低考虑到 \(A\) 的第 \(i\) 位,总共进位了 \(j\) 次,\(a + b\)(小于 / 等于)\(A\) 且(不接受 / 接受)低一位的进位时的 \(a, b\) 的取值方案数。以 \(i\) 作为阶段,从大到小进行转移。则答案为 \(\displaystyle \sum_{j \ge \alpha} f(0, j, 0, 0) + f(0, j, 1, 0)\)

时间复杂度为 \(\mathcal O \!\left( \log_p A \!\left( \log A + \log_p A \right) \right)\)评测链接

cf585F

\(s\) 中的所有长度为 \(\displaystyle \left\lfloor \frac{d}{2} \right\rfloor\) 的子串搞出来建个 AC 自动机,然后数位 DP 一下就做完了。

时间复杂度为 \(\mathcal O (|\boldsymbol{\Sigma}| \cdot |s|d^2)\)评测链接

2019-11-30

cf708E

代码写的很乱,讲个大概思路:

可以发现上下连通当且仅当相邻层剩下来的区间有交,那么我们考虑自上而下 DP,状态就为当前剩下的区间:
\(dp(i, l, r)\) 表示考虑前 \(i\) 层,第 \(i\) 层的区间为 \([l, r]\) 时的概率,转移时枚举上一层的区间即可。

这个做法状态数就是 \(\mathcal O (n m^2)\) 的了,不能接受。

考虑区间 \([l, r]\),和它有交的区间 \([l', r']\) 需要满足 \(r' \ge l\)\(l' \le r\),当然还有 \(l' \le r'\)
条件比较复杂,容斥一下可以发现也等价于所有区间减去 \(r' < l\) 的区间减去 \(l' > r\) 的区间(前提是满足 \(l' \le r'\))。

那么现在转移就方便了,等于上一层的 DP 值的总和减去上述两个限制条件。

考虑令 \(f(x)\) 表示所有满足 \(l > x\) 的区间的 DP 值之和,令 \(g(x)\) 表示所有满足 \(r < x\) 的区间的 DP 值之和。
(由对称性容易发现 \(g(x) = f(m + 1 - x)\)

这时状态数仍然是 \(\mathcal O (n m^2)\) 的,考虑直接利用上一层的 \(f\)(或 \(g\))求出这一层的 \(f\)(或 \(g\))。

推一波式子就发现,确实是可以求的,然后按照式子进行计算就行了。

计算时需要预处理形如 \(\displaystyle \binom{k}{i}\) 的组合数。

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

2019-12-02

cf568C

显然前面的形式是个 2-SAT,建图、Tarjan 求强连通分量、bitset 求传递闭包一气呵成。

构造方案时直接 DFS,要记一下当前是否已经大于原串(也就是后面的可以任意填),可以证明递归到的状态是 \(\mathcal O (n)\) 的,还要用数组记一下不能选的点,这里也用 bitset 优化,是 \(\mathcal O (n^2)\) 的。

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

cf611G

考虑固定对角线的一点 \(x\),对于另一点 \(y\)\(\vec{xy}\) 左侧的面积小于等于总面积的一半对应的 \(y\) 是一段区间,双指针求出区间的分界点后,把公式套上去算就完事了,需要预处理多个前缀和数组,注意控制精度别爆 long long 了。

时间复杂度为 \(\mathcal O (n)\)评测记录

2019-12-03

cf582E

答案即这 \(n\) 个方程左侧的取值恰好等于右侧时的方案数。

上表达式树后,很难直接获得信息,所以考虑维护方程左侧在 \(2^n\) 种取值中,取到每一种取值的方案数。

即在子树中,对于每个数 \(0 \le x < 2^n\) 维护满足方程左侧的状态压缩后恰好为 \(x\) 的替换 ? 的方案数。

直接在表达式树上合并信息即可,用 FWT 实现快速信息合并。

时间复杂度为 \(\mathcal O (|s| n 2^n)\)评测记录

cf504E

对原树进行字符串哈希,每个点存根到它的字符串和它到根的字符串的哈希值,就可以 \(\mathcal O (1)\) 提取一条没有拐点的链的哈希值。

\(a \to b\)\(c \to d\) 两段路径分解为 \(\mathcal O (\log n)\) 条重链区间的并。

每次尝试将 LCP 扩展两条路径的当前区间长度的最小值,也就是至少消掉一个区间,这样最多 \(\mathcal O (\log n)\) 次消完。

如果扩展失败,在区间上进行二分查找即可,复杂度也是 \(\mathcal O (\log n)\)

时间复杂度为 \(\mathcal O (n + m \log n)\)评测记录

  • WA6 原因:哈希的模数选太大了,导致做加减法也要加 (LL),但是我没加。

2019-12-07

agc032_f

丢人,看了 题解 才会,也不知道怎么写题解。

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

2019-12-13

agc027_d

如图所示,黑白染色后,每个黑色格子按照每个正 / 反斜对角线填上两个质数的乘积。

\(m=1\),则白色格子上的数为相邻四个黑色格子上的数的 \(\mathrm{lcm} + 1\)

稍微调整一下质数的顺序,就可以做到数不超过 \(10^{15}\) 了。

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

2019-12-17

agc032_d

题意为:将一个数往右扔需要花费代价 \(A\),往左扔需要花费代价 \(B\),问排序的最小代价。

\(pos_i\) 表示数 \(i\) 现在所在的位置,也就是说将 \(pos_i\) 增加需要 \(A\) 的代价,减少需要 \(B\) 的代价。

那么令 \(dp(i, j)\) 表示考虑前 \(i\) 个数,\(pos_i = j\) 时的最小代价即可。

注意 \(j\) 的取值只需要标记是 \(1, 2, \ldots , n\) 或者是 \((-\infty, 1), (1, 2), (2, 3), \ldots, (n - 1, n), (n, +\infty)\) 即可。

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

2019-12-19

agc037_d

把最终应该在同一行中的数染成同一种颜色,即 \(1 \sim m\)\(1\) 号颜色,\((m+1) \sim 2m\)\(2\) 号颜色,以此类推。

可以发现总共有 \(n\) 种颜色,每种颜色恰好有 \(m\) 个数。

第一次变换后的矩阵应当满足:每一列中的 \(n\) 个位置,恰好包含了所有 \(n\) 种颜色。

考虑从左到右一列列地确定第一次变换后每一列应当有哪些数。

建立二分图:如果第 \(i\) 行的第 \(j\) 个位置是颜色 \(k\),则左侧的 \(i\) 号点向右侧的 \(k\) 号点连一条边。

可以发现只要找到 \(m\) 个完美匹配就行了,一个完美匹配对应着某一列的染色情况。

\(m\) 遍匈牙利算法即可。

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

2019-12-20

arc095_f

考虑以数值从小到大的顺序加入 \(p\) 中的元素,可以发现原树必须是毛毛虫,然后瞎调整一下就完事了。

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

2019-12-21

arc098_f

解法基于这样一个重要事实:存在一种最优情况满足不会回到已经捐款过的节点,因为如果回去了,可以把捐款时间点挪后。

考虑 \(C_i = \max \{ A_i - B_i, 0 \}\),可以发现原题意等价于:捐款后剩余钱数也需要大于等于 \(C_i\)

转化后的题意就好考虑了,容易发现对于 \(C_i\) 最大的点 \(u\),因为捐款后不会返回,所以假如删除 \(u\) 后把整张图分成了若干个连通分量(假设为 \(k\) 个),需要先处理 \(k-1\) 个连通分量,再在 \(u\) 上捐款,然后移动到最后一个连通分量里进行捐款,并且再也不回到 \(u\)

容易发现这个结构类似于按照 \(C_i\) 从小到大的顺序建一个类 Kruskal 重构树,以 \(C_i\) 最大的点 \(u\) 为根,其每一个子树表示 \(k\) 个连通分量中的一个。

\(dp(x)\) 表示在 \(x\) 的子树内捐款最少需要准备多少钱,自底向上转移即可。

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

2019-12-22

cf639E

通过调整法不难证明,最优策略为按照 \(t_i / p_i\) 升序依次选取,也就是说和 \(c\) 无关。

对于 \(t_i / p_i\) 相同的,任意顺序均可,那么我们可以求出某个题的最快解决时间和最慢解决时间(在最大化总得分的条件下)。

令第 \(i\) 题的最快 / 最慢解决时间分别为 \(l_i, r_i\)

也就是询问对于任意一组 \(p_i < p_j\),均需要满足 \(p_i \!\left( 1 - \frac{l_i}{T} \right) < p_j \!\left( 1 - \frac{r_j}{T} \right)\)

进一步地,可以发现如果 \(p_i < p_j < p_k\),只需检查 \(i, j\)\(j, k\) 而不需要检查 \(i, k\)

所以把所有题目按照 \(p_i\) 升序排序,对于相邻的 \(p_i\) 相同的块分别检查即可。

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

2019-12-23

cf559E

先把所有灯按照 \(a_i\) 递增排序。

我们考虑最右侧被照到的点是哪个灯的,假设是 \(i\) 的,如果 \(i = n\),则可以向左照或者向右,否则当然就是只能向右。

我们先考虑 \(i\) 向右的情况,可以发现 \(i + 1\)\(n\) 这之中的所有灯,最优选择都是向左,因为向右要么与条件冲突,要么没有意义。

这之中的所有灯都向左了,可能还会照到其它更左侧的灯,同理这些灯的选择也是向左,然后照到更多的灯,这样连锁反应下去最终会停止。通过预处理区间中的 \(a_i - l_i\) 的最小值,我们可以在 \(\mathcal O (n \log n)\) 的时间内(利用 ST 表)求出 \(lb(i)\),表示如果 \(i\) 向左照,最多能影响到多远,这个坐标必然是某一个灯的 \(a_j - l_j\),我们记下这个编号 \(j\) 即可。

然后考虑这样下去停下了,假设 \(j\) 以及 \(j\) 右侧的所有灯(除了 \(i\))都向左照了,我们可以处理出被照亮的区间的最左端点,这个端点要么是某个灯的 \(a - l\),要么是 \(a_i\) 本身。

然后考虑处理更左侧的段即可,此时我们发现多了个右侧的左端点的限制,如果照亮的部分超过了右边区间的左端点则不算,这个其实区别不大,只要算照亮右边区间左端点左侧的贡献即可。

还有一个情况是 \(n\) 本身就向左照了,经过上面的分析,发现这个情况其实更简单,只要用 \(lb(n)\) 直接转移就行了。

所以这是一个有 \(n\) 个状态(因为每次右侧区间的左端点只有可能是 \(a_i\) 或者 \(a_i - l_i\)),每个状态从 \(n\) 个状态转移,每次转移代价为常数的动态规划。

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

2019-12-24

cf576E

加删边,问是否是二分图 —— 线段树分治,带权并查集。

一个线段树分治的技巧:可以任意修改在当前时间点之后的加入操作,即当前时间点为 \(i\) 时,可以任意修改满足 \(i \le l \le r \le q\) 的操作 \([l, r]\)

线段树分治 + 带权并查集板子题。

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

2019-12-25

cf578E

也就是把 \(s\) 分成最少数量的子序列,满足每个子序列都是 LR 交替的,而且它们按照某种顺序拼接起来也是 LR 交替的。

先尝试抛开第二个条件,求出最少的子序列个数,满足每个子序列都是 LR 交替的。

可以证明「每次增加一个字符,如果之前有结尾为相反字符的子序列的话,接在后面,否则自成一个新的子序列」的贪心是正确的。

考虑分别有若干(可能是 \(0\))条开头和结尾分别是 LL,LR,RL,RR 的子序列,如何将它们拼成拼接位置也是 LR 交替的子序列。

如果既有 LR,也有 RL,考虑把所有 LR 拼起来,所有 RL 也一样,但是它们并不能直接相连。
考虑哪一个的最后一个字符的位置更靠后,把这个字符接在另一个序列的后面即可。
这样子能构造出仅剩一条 LR 或者 RL。

再考虑 LL 和 RR,因为只有最多一条 LR 或者 RL,肯定有办法直接拼上,分类讨论即可。

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

2020-01-06

cf526F

不知道哪里来的原题,有多种做法:

  1. 单调栈 + 线段树:扫描线,固定右端点,右端点往右扫,维护一个区间中的左端点形成的区间 \([l, r]\)\((max - min) - (r - l + 1)\) 的最小值个数。

  2. 线段树:扫描线,从值域的角度考虑,固定最大值,从小往大扫,维护一个区间中的最小值形成的位置集合的连续段数量的最小值个数,我写的是这种做法。

  3. 题解的做法是分治,把序列从正中间划分成两半,先递归处理两半,然后分四种情况讨论跨过中点的部分。

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

2020-01-08

cf571D

根据 U, M 操作建出两个 Kruskal 重构树(类似物),然后对于每个 A, Z 操作在对应节点上挂链。

一次 DFS 求出每个 Q 操作对应的上次袭击时刻,再一次 DFS 求出答案,都使用树状数组维护。

题解用的是带权并查集,不失为一种好方法。

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

cf575I

转成五种不同的偏序的叠加,二维树状数组维护。

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

2020-01-10

arc100_f

称满足题目条件的序列是合法的,则答案为任意序列出现 \(A\) 的次数减去不合法序列出现 \(A\) 的次数。

其中,任意序列出现 \(A\) 的次数即为 \((N - M + 1) K^{N - M}\)(先枚举位置,再枚举剩下的字符)。

考虑统计不合法序列出现 \(A\) 的次数,这里分三类讨论:

  1. \(A\) 就是合法的,则包含 \(A\) 的序列都是合法的,所以总数为 \(0\)

  2. \(A\) 中存在相同的字符,这意味着连续 \(K\) 个不同字符的连续段,只可能出现在 \(A\) 的左侧或右侧,不可能覆盖 \(A\)。也就是说 \(A\) 的左右两侧是独立的,可以枚举 \(A\) 出现的位置,然后算出左右两侧的方案数相乘再相加。对左右两侧分别进行 DP,求出往 \(A\) 的左侧或右侧添加若干个字符,且得到的序列不合法的方案数。最后相乘再相加即可。

  3. \(A\) 不是合法的,但是不存在相同字符,这时必然有 \(M < K\)。使用类似上例中的 DP 方式,统计出所有不合法序列中,连续 \(M\) 个不同字符的连续段个数。可以发现每个这样的连续段,有恰好 \(\dfrac{(K - M)!}{K!}\) 的概率等于 \(A\)(考虑字符可以任意排列,方案数为 \(K!\),但是恰好排列出 \(A\) 的方案数只有 \((K - M)!\))。所以连续段个数除以 \(A_K^M\)(排列数)就是要求的总数。

\((N - M + 1) K^{N - M}\) 减去不合法序列出现 \(A\) 的次数就是答案。DP(加前缀和优化)的复杂度即为 \(\mathcal O (NK)\)

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

cf704D

先离散化,然后套路地转二分图网络流模型。

如果一个点染红色(假设 \(r < b\),如果不是的话就红蓝反过来),那条边的流量就为 \(1\),否则为 \(0\)

那么就是要求最大流,然后发现每行每列限制其实就是个上下界,套有源汇有上下界最大流板子即可。

点数边数都是 \(\mathcal O (n)\) 的,使用 Dinic 实现,因为二分图中间层是单位容量,所以复杂度为 \(\mathcal O (n \sqrt{n})\)

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

agc032_c

题目告诉我们这张图是个连通图,那么首先要有欧拉回路,否则无解。

如果存在度数 \(\ge 6\) 的点,从它开始的欧拉回路就会三次回到它本身,必然有解。

如果没有度数为 \(4\) 的点,只有度数为 \(2\) 的点,那就是说这张图是一个环,不可能有解。

现在只剩至少一个度数为 \(4\) 的点和度数为 \(2\) 的点,我们把度数为 \(2\) 的点缩掉:
留下来的图就只会有度数为 \(4\) 的点,并且可能存在重边和自环。

如果只有一个度数为 \(4\) 的点,那必然是它连了 \(2\) 条自环,无解。

如果只有两个度数为 \(4\) 的点,那么就有两种情况:

  1. 两点之间有 \(2\) 条边,每个点有 \(1\) 个自环:有解。

  2. 两点之间有 \(4\) 条边:无解。

如果存在 \(\ge 3\) 个度数为 \(4\) 的点,考虑从某个点出发的欧拉回路,它必然会回到这个点两次,
在这两个圈中,如果存在一个点在其中一个圈中出现了两次,就能分离出另一个圈;
否则必然存在两个点,分别出现在两个圈中,拆下来也可以分别组成三个圈。

所以只要判断只有两个度数为 \(4\) 的点的情况,是上面的哪一种即可。随便写个遍历就能判断了。

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

2020-01-14

arc089_f

\(N \le 70\) 的数据范围不怀好意,果然是一个神题。

首先可以观察到,对于最终形成的序列,取出其中一个极大有颜色连续段,可以发现最短的染色序列有如下规律:
(这里把相同的连续多个字符缩成一个字符,显然对结论没有影响)

  1. r:最短染色序列为 r

  2. brbbrrbr:最短染色序列为 rb

  3. brbrbrbbrbrrbrbr:最短染色序列为 rb?? 表示可以填任何字符)。

  4. brbrbrbrbrbbrbrbrrbrbrbr:最短染色序列为 rb??

以此类推。

不难发现,只要染色序列包含了最短染色序列为子序列,那么也一定可以染成最终的模样,而不包含则一定不行。

我们把这些序列依次编号,有 \(x\)b 的编号为 \(x + 1\)(和上面的编号相同)。

那么某个最终状态就可以被表示为一个序列,比如 wwbbrbrbrrrwwrrwwrbwbbb 就可以被表示为 \(\{4, 1, 2, 2\}\)

也就意味着,如果 \(s\) 含有 rb??rrbrb 作为不相交子序列,就可以得到这个最终状态。

如何判断是否包含呢?容易想到一个贪心的做法:按照编号从大到小排序,先按顺序把 r 安排上,再把 b 安排上,最后安排剩下的 ?,正确性用调整法不难证明。

但是这又有什么用呢,不是要计数吗?

可以发现只要两个最终状态被表示成的序列(排序后)相同,那么这两个最终状态就是等价的。所以只要枚举对应的序列就行。

这个最终状态对应的序列方案数其实类似于整数分拆,因为那些编号的和不能太大,而且是无序的。

假设 \(N = x\) 时可行的序列方案数为 \(f(x)\),则有 \(f(x) \le x \mathrm{Partition}(\lfloor x / 2 \rfloor)\)

实际上,当 \(N = 70\) 时,\(f(N)\) 也只有 \(418662\)

那么有了序列,如何计算有多少个最终状态对应到这个序列呢?

实际上就是一个多重组合数(序列的重排方案数)乘以用隔板法计算的填充方案数(也就是 brbwbwr 变成 wwrrbrrbwrbbrwwrrw,有 \(13\) 个地方可以插入新字符,有 \(11\) 个新字符可供插入,所以乘上一个 \(\binom{11 + 13 - 1}{13 - 1}\))。

具体细节详见代码。

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

agc039_d

如图所示,单位圆上的三点组成 \(\triangle ABC\),内心为 \(I\),令 \(A', B', C'\) 分别为弧 \(BC, AC, AB\)(不经过 \(A, B, C\) 的那一段)的中点。

则由鸡爪定理和同一法可知,\(AIA'\)\(BIB'\)\(CIC'\) 均三点共线;
\(B'I = B'C\)\(A'I = A'C\),所以 \(IC \perp A'B'\),所以 \(C'I \perp A'B'\)

同理可得 \(A'I \perp B'C'\)\(B'I \perp A'C'\),即 \(I\) 同时为 \(\triangle A'B'C'\) 的垂心 \(H'\)

由欧拉线定理可得,\(\overrightarrow{OH'} = 3 \overrightarrow{OG'} = \overrightarrow{OA'} + \overrightarrow{OB'} + \overrightarrow{OC'}\)

所以要求 \(E(I) = E(H')\) 只要求 \(E(A') + E(B') + E(C')\) 即可。

枚举点对计算就可以了。

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

2020-01-15

cf639F

也就是,给定一张无向图,每次询问在原图的基础上加一些边,然后问一些点是否在同一个边双连通分量中。

众所周知,一张图将边双连通分量缩点后构成一个森林,先把原图的这个森林建出来(用 Tarjan)。

然后将新加的边的端点和询问的点作为关键点,建虚树(代码中用了树剖求 LCA),然后加边跑 Tarjan 即可。

时间复杂度为 \(\mathcal O (n + m + \sum (n_i + m_i) \log (n_i + m_i))\)评测链接

posted @ 2019-10-30 14:22  粉兔  阅读(5686)  评论(10编辑  收藏  举报