训练记录PART8 2019.2.14~2018.4.4
友情提醒:大部分题选自opentrains,以后有训练需要的同学慎重查看。
T135-NAIPC 2018 B
题意:给出一个 \(N\) 个点 \(M\) 条边的图。问有多少种选取点集 \(V\) 的方法,满足 \(V\) 的导出子图是一个团,而 \(N-V\) 的导出子图是一个独立集。\(N,M \leq 2 \times 10^5\)。
题解:看不懂 claris题解 里的神奇做法。
我们每次考虑所有点中度数最大的点 \(O\),考虑它在哪个点集里。假设它在 \(N-V\) 中,那么所有和 \(O\) 有边的点 \(P_1,P_2,\dots,P_k\) 必须在 \(V\) 中(当然,它们两两之间也必须有边),此时 \(P_i\) 的度数至少是 \(k\) 了。因为 \(O\) 的度数只有 \(k\),所以 \(V\) 中必须恰好是 \(P_{1 \sim k}\) 这些点。我们只需支持快速判断 \(P_{1 \sim k}\) 是否是一个团,以及 \(N-V\) 是否是一个独立集。假设它在 \(V\) 中,那么之前和 \(O\) 没有边的那些点必然在 \(N-V\) 之中,而且它们对于后续的判断已经没有用处了,我们可以直接从图上删掉这些点。即:我们只需考虑 \(P_{1 \sim k}\) 这个点集,哪些划到 \(V\) 里,那些划到 \(N-V\) 里。变成了一个子问题,递归下去即可。
找 \(P_{1 \sim k}\) 时复杂度是算在边上的;所以每层递归里,常数次枚举 \(P_{1 \sum k}\) 复杂度依然是线性的。如何判断 \(P\) 是一个团呢?我们只需实时维护每个点的度数。每次找到 \(P\) 后,我们暴力枚举目前考虑的点集里除掉 \(P\) 后的点集 \(Q\) (这些都是不和 \(O\) 有边的点)。这些点永远也没有用处了,我们可以枚举它们的所有边,将出点度数减一,并删除这些点。均摊复杂度 \(O(N+M)\),实现时有很多细节。
T135-NAIPC 2018 C
题意:有 \(N(\ leq 16)\) 个灯泡,给出它们的初始亮暗的情况。每秒钟你可以什么都不干,或者至多拨动一个开关 \(i\):假设现在时间是 \(t\),第 \(t\) 秒 \(i\) 状态翻转,第 \(t+1\) 秒 \(i+1\) 状态翻转……一直到灯泡序列末尾后影响停止。问最早什么时候灯泡能全亮的景象。
题解:如果直接状压,很难处理翻转的延续效果,强行记状态会达到 \(O(2^N \times 2^N)\) 的规模。不妨假设枚举最终时刻 \(T\)(显然 \(T \leq N\)),这样子就可以快速 DP 了。设 \(f_{i,S}\) 表示到了第 \(i\) 秒钟,灯泡亮暗状态是 \(S\) 的情况能否达到。转移时如果枚举拨动开关 \(i\),我们可以根据 \(T\) 算出它的翻转区间,直接集体翻转即可。总复杂度是 \(O(2^N \times N^3)\)。因为 \(T\) 远远不到 \(N\),且常数很小,可以通过此题。
观察最优解的翻转情况,我们可以得到一个结论:存在一种最优解,它的所有翻转区间的长度都不同(因为每一秒才能拨动一次,持续长度不断递减)。显然,最后的答案就是最长区间的长度。那么可以设 \(f_{i,S}\) 表示到了时间 \(i\),状态 \(S\) 是否能达到。每次枚举等于当前时间 \(i\) 的长度区间来异或,复杂度 \(O(2^N \times N^2)\)。
T137-2018 ICPC CERC G
题意:维护一个 \(N \times M(N \leq 50,M \leq 100000)\) 的网格。有 \(L(\leq 2 \times 10^5)\) 个操作,分为两种:①将 \([x1,y1] \sim [x2,y2]\) 这个矩阵染成 \(1\)。②问点 \([x1,y1]\) 和 \([x2,y2]\) 是否能通过 \(1\) 的连通块到达。
题解:本来的做法是,对于总的 \(N \times M\) 的网格,维护一个总体的连通性并查集。对于每一行再单独开一个并查集,\(f_{i,j}\) 表示与第 \(i\) 行位置 \((i,j)\) 的紧挨着的集合相同的最远的列。每次连通一个矩阵的时候,暴力枚举每一行维护。每次从 \(y1\) 开始跳 \(f\),如果此时 \(f_{i,j}\) 和 \(j\) 的集合已经相同,则重置 \(f_{i,j}\)。再将这么多行找出的集合一一在 \(g\) 处合并即可。复杂度 \(O(NM \alpha (NM)+LN \alpha M)\)。
注意这是有问题的。比如染了 \([1,1],[1,1]\) 和 \([1,2],[1,2]\) 后,这两个点也变成了同一个连通块。怎么 fix 呢?
暴力的做法是,对于矩阵周围的一圈再判一下,如果某个格子颜色是 \(1\),则可以和当前块连起来。对于前后两列,可以这么暴力维护,因为总共只有 \(2N\) 个格子。当然,我们要额外开 \(N\) 个树状数组来快速判定一个格子是否是 \(1\),复杂度加上 \(O(LN \log M)\)。
上下两行怎么办呢?我们可以修改之前对于网格的定义,维护的不是网格,而是网格上下一条条“横线”。\(x1 \sim x2\) 的网格对应标号为 \(x1-1 \sim x2\) 这些横线。这样,对于上下边相邻的格子,我们自然而然地将它们连接在了一起,而且总复杂度不变。
T143-2015 ICPC - World Finals E
题意:给出 \(N(\leq 4000)\) 个长度 \(\leq 4000\)、只有三种字符的字符串。将它们划成两个集合,使得每个集合都能排成一列,前一个是后一个的子序列。打印一种方案或输出无解。
题解:按长度排序。如果我们能求出 \(d_{i,j}\) 表示串 \(i\) 是否是 \(j\) 的子序列,就可以通过经典的 \(O(N^2)\) dp求出答案。
但是这是无法预处理的。其实直接贪心就好了。最初,不妨设两个集合 \(p\) 和 \(q\) 都是空串。从前往后考虑到 \(i\)。性质:如果 \(i\) 不是 \(i+1\) 的子序列,\(i\) 和 \(i+1\) 必然分属不同的集合。这样,我们只需判断一下怎么分配,而且分配完后,之前怎么选和之后怎么选是互不影响的。如果 \(i\) 是 \(i+1\) 的子序列,直接把 \(i\) “绑定” 在 \(i+1\) 上,往后处理即可。这样走了 \(O(N)\) 步,只会 \(check\) \(O(N)\) 次子序列,复杂度 \(O(\alpha N^2)\),\(\alpha\) 是字符集大小。
T143-2015 ICPC - World Finals H
题意:有一座底边 \(w\),高为 \(h(h<w)\)的直角三角形的山,山是坚实的固体。要把底边打成一个隧道,但是要把挖出来的泥土运到山坡上(斜边)。所以对于底边的每一个 \(dx\),需要运送一定的距离(可以向左运,也可以向左运到最右边再向上运到顶)。现在还要在山里竖直地打 \(N(\leq 1000)\) 个竖直的泥土运送轨道,这样一处泥土还可以运到某个轨道底部,然后竖直运送上去。麻烦的是,这 \(N\) 个轨道自身也会产生泥土,每单位都要运送到最顶上(越往左,额外运输量越少,但是优化量也少)。求这些轨道的最佳位置,使得总运土距离(积分)最小。
题解:太有趣了!由 \(h<w\) 的性质,每一处的泥土肯定运到相邻的轨道上。不妨设第 \(i\)段的被轨道划分的段长度是 \(x_i\),总答案就是 \(\sum \frac{kx_{i-1}+x_i+kx_{i+1})^2}{4} - \frac{(kx_{i-1})^2}{2}\) (减掉是因为重复算了)。算到这里可能就凉了。强做应该也可以?强行拉格朗日乘数法,观察一些,发现每个方程只有三个相邻的未知数,且它们的系数是一样的。把 \(\lamba\) 配进去后相当于解递推式。
其实做法很傻逼。重要性质:对于一个三角形,求出了 \(N\) 条线后,无论三角形怎么扩大缩小,\(N\) 条线的位置依旧是线性分配的。归纳法求解,\(1\) 条线显然是能解的。现在要求画 \(N\) 条线的方案,设最后一条线位置 \(x\)。根据 \(N-1\) 条线的答案,我可以求出其他线的位置(用 \(x\) 表示)。最后就是二次函数求极值。复杂度 \(O(N^2)\)。
T143-2015 ICPC - World Finals M
题意:考虑这么一个问题。考虑二进制位数 \(k(k \leq 16)\),给出 \(N\) 个互不相同的数 \(x_i(0 \leq x_i < 2^k)\),对于 \(0 \sim 2^k-1\),你都要求一个 \(j\),使得 \(x_j^i\) 最大。现在把这些 \(j\) 都告诉你,问序列 \(x_i\) 有多少种可能。
题解:称给出的 \(j\) 的逆序为 \(p\)。从高到底考虑每一位 \(i\),那么对于所有 \(x < 2^i\) 和 \(y \geq 2^i\), \(p_x\) 和 \(p_y\) 要不全相等,要不全不等。如果全不相等,划成两个独立的子问题,继续递归下去即可;如果全相等,左右状态等价,递归其中一个状态,答案乘 \(2\)。总复杂度 \(O(N \log N)\)。
T145-Petrozavodsk Winter 2019 - Oleksandr Kulkov Contest A
题意:给出长度为 \(3^K(K \leq 12)\) 的数组 \(a\) 和 \(b\)。 \(c_k=\sum \limits_{mex_k(i,j)=k} a_i b_j\)。求数组 \(c\)。定义 \(mex_k(x,y)\) 为,对于 \(x\) 和 \(y\) 的每一个三进制位 \(i (0 \leq i < k)\),求 \(mex(x_i,y_i)\),将结果看成三进制下的一个数 \(z\),则 \(mex_k(x,y)=z\)。
题解:\(n\) 恰好等于 \(3^k\),猜测可以像分治乘法一样,可以通过减少递归优化复杂度。
设过程 \(Solve(a,b,k)\),考虑目前下标的最高位 \(k\),\(a\) 和 \(b\) 的 “\(mex\)” 卷积的答案。
分别将 \(a\) 和 \(b\) 按下标的第 \(k\) 位的不同划成三段,记作 \(a_k(0 \sim 2)\)。首先由 \(c_k(0) = \sum Solve(a_k(1/2),b_k(1/2))\)。我们可以暴力将 \(a_k(1) ,a_k(2)\) 以及 \(b_k(1),b_k(2)\) 的数值合并,缩减为一个 \(\frac{N}{3}\) 的子问题。
再考虑 \(c_k(2) = Solve(a_k(1),b_k(0))+Solve(a_k(0),b_k(1))\),可以直接缩减为两个 \(\frac{N}{3}\) 的子问题。
\(c_k(1)\) 很难求,但它可以用容斥来快速求出。将 \(a_k\) 和 \(b_k\) 全部合并,算出答案后减去前两种的即为所求,缩减为一个 \(\frac{N}{3}\) 子问题。
总复杂度为 \(T(N)=4T(\frac{N}{3})+O(N)\),即 \(O(4^K)\)。
T145-Petrozavodsk Winter 2019 - Oleksandr Kulkov Contest F
题意:给出一棵 \(N(\leq 10^5)\) 个点的带权生成树,再给出一些额外的边。我们称一个点 \(S\) 是合法的,当且仅当 \(\forall T,Tree_{min}(S,T) \geq Path*_{min}(S,T)\)。\(Tree_min(S,T)\) 表示 \(S \sim T\) 树上路径权值最小的边,\(Path*_min(S,T)\) 表示任意一条从 \(S\) 到 \(T\) 的简单路权值最小的边。输出所有合法点。
题解:从大到小枚举边。考虑一条权值为 \(w\) 的树边 \((u,v)\)(此时所有权值 \(>w\) 的树边和非树边已加入并查集),如果 \(u\) 和 \(v\) 在一个集合里,容易证明,这个集合里的所有点都不合法,但这个 \(check\) 在树边边权有重复的情况下并不是充分的。可以再加一个 \(check\),每次合并非树边时,如果 \((u,v)\) 不在同一个集合,那么它们合成的新点集都不合法(因为之后必然存在树边,树边两侧的点对都错了)。我们可以使用启发式合并和标记系统来维护这些操作。复杂度为 \(O(N \log N)\)。
比赛的时候糊了一个 \(O(N \log^2 N)\) 的猥琐做法。借鉴 NOIP2014 货车运输,将所有边做一个最大生成树,设为B。那么任意两点所有路径权值最小边的最大值即为树上路径最小边。对 \(A\) 树点分,每次考察子树内点 \(x\) 到子树外点 \(y\) 是否合法。对 \(B\) 树做点分树,用来快速维护一个点对于一个点集的询问。设 \(S_x\) 表示点 \(x\) 到 \(A\) 树分治中心边权最小值,\(T_x\) 表示点 \(x\) 到 \(B\) 树某一层分治中心(需要枚举)的边权最小值。对于一个固定的 \(x\),所有 \(y\) 必须满足 \(min(S_x,S_y)>=min(T_x,T_y)\)。分类 \(S_x\) 和 \(T_x\) 的大小关系,转化为维护 \(S_y\) 和 \(T_y\) 的极值。
维护的是极值,没有可加性,所以容斥会比较麻烦。 \(A\) 树上可以通过前缀后缀做一遍来避免算重。\(B\) 树上通过维最大极值和(来自不同子树的)次大极值来实现。总复杂度为 \(O(N \log^2 N)\)。