Codeforces 倒刷计划
CG#1G
题意:给出一棵 \(N(\leq 5 \times 10^5)\) 个点的树,有些点已经被染成白色。甲乙两人博弈,甲每次把一个没染过的点染成白色,乙染黑色,甲先操作。任意时刻,如果出现一条同色的三个点的链,该颜色方就胜利。若双方都执最优策略,判断胜负或平局。
题解:如果有度数为 \(4\) 的点,白方第一步就可以选那个点,必胜。类似地,如果存在一个度数为 \(3\) 的点,且它有两个支链长度至少为 \(2\)(黑方一次只能堵住一个),白方依然必胜。由该结论得到推论:如果有至少 \(3\) 个度数为 \(3\) 的点,白方必胜。现讨论图里有几个度数为 \(3\) 的点。
① \(2\) 个,记为 \(p\) 和 \(q\)。由上述结论,除了中间一条长链,\(p\) 和 \(q\) 另外两侧的支链必然只有一个点(否则白方胜)。而且,如果图中至少有一个白色点已经涂好,也必然白方胜。注意此时不一定是平局,还要观察中间长链的奇偶性。
② \(1\) 个,记为 \(p\)。显然 \(p\) 除了一条长链连出去,另外两侧必然只有一个点。如果无任何初始白点则平局(白方每走一步,黑方贴着它左边下)。如果有一个不在长链末端的白点则白方胜;否则要判断长链的奇偶性。
③ \(0\) 个。就是一条链。位于中间的已经染过的白色格子,或者存在距离差为偶数的两个白色格子都是白方赢,否则平局。
CR#534B
题意:交互题。要猜出一个未知正整数 \(a(1 \leq a \leq 10^9)\)。每次给judge两个数 \(x\) 和 \(y\),返回 \(x \mod a \geq y \mod a\) 是否成立。最多进行 \(60\) 次这样的操作。
题解:如果我们询问一组 \((t,2t)\),考察会出现怎样的结果:当 \(t<a<2t\) 时必然不成立,当 \(t \geq 2t\) 时必然成立,其余情况不确定。我们想借助后面两个条件来二分,所以会要求先估计出 \(a\) 的一个下界。
有 \(60\) 次操作限制,所以还能再进行一次类似于二分的操作。我们可以先从小到大询问 \((2^k,2^{k+1})\),找到第一个不成立的区间:这时候就确定了,\(a\) 必然落在区间 \((2^k,2^{k+1}]\)。然后再对 \(a\) 直接二分。稍作修改,每次询问 \((2^k,mid)\),即可确定二分方向。
CR#534C
题意:给出一个每个点度数至少是 \(3\) 的简单连通图。读入 \(K(K \leq N \leq 2 \times 10^5)\),或者找到一个长度至少为 \(\frac{N}{K}\) 的简单路,或者找到 \(K\) 个环,满足:①环长至少都是 \(3\)。②环长不能是 \(3\) 的倍数。③每个环里至少要有一个点不在别的找到的环里(我们称之为代表点)。
题解:只要利用上题目中的古怪条件和限制就能出解。首先,简单路是十分Hard的,所以必然是 DFS 式地找简单路,并搜出一棵生成树。如果没有达到第一个要求,那么我们搜出的生成树高度 \(<\frac{N}{K}\),即至少有 \(K\) 个叶子。这和要求的环的数量吻合,所以尝试把这些叶子作为代表点去找那 \(K\) 个环。因为每个点度数至少为 \(3\),所以叶子至少有两条不同的返祖边,它们会形成 \(3\) 个环。鸽笼原理,必然有一个环长不是 \(3\) 的倍数且至少为 \(3\) 的环。
CR#534D
题意:给出 \(N(\leq 10^6)\) 个正整数 \(a_i(\leq 10^{12})\)。可以选择一些数,除掉一个自己的约数 \(d_i(d_i | a_i)\)(且满足 \(d_i \leq K\))。每一个数还有一个修改代价 \(p_i\)。对于你选择修改的数的集合 \(S\),总代价为 \(|S| \times \sum \limits_{i \in S} p_i\)。要使得所有数的GCD为1,求最小总代价。
题解:将初始的 GCD 质因数分解,不同质因子个数 \(m \leq 11\)。显然,我们最终目的是将这 \(m\) 个质因子划成一些集合,每一个集合对应一个数(同时要符合 \(k\) 的要求),使得 “集合数 \(\times\) 代价和”最小。
将 \(a_i\) 对这 \(m\) 个质因子分解,得到一些 \(m\) 维向量。 完全相同的向量最多只需保留代价最小的 \(m\) 个。
标程的做法是,直接暴力枚举所有合法的划分。每个集合要配一个不同的数,所以要预处理能覆盖集合 \(S\) 的代价前 \(m\) 优的数字,然后把这些集合和它们拓展出来的这些数字做一个匹配。每次匹配是,左侧最多 \(x\) 个点(\(x\) 为集合数),右侧最多 \(x^2\) 个点,单次复杂度 \(O(x^3)\),总复杂度 \(\sim 10^8\)
还有一个 DP 解法。设 \(f_{i,j}\) 为:现在覆盖了集合 \(i\),且正好选了 \(j\) 个集合的最小代价和。把可能成为答案的向量都丢进去 DP 一遍。我觉得复杂度存疑。
CR#532F
题意:给出 \(N(\leq 5 \times 10^5)\) 个数和 \(Q(\leq 5 \times 10^5)\) 个询问,每次给你 \((l,r)\),问 \(l \sim r\) 这些数里选一些异或能凑出的最大的数是多少。51nod 1577原题。
题解:显然是区间提取线性基。线段树暴力是 \(O(N \log^3 N)\) 的,采用优美的 CDQ 分治可以做到 \(O(N \log^2 N)\)。
有一种比较玄学的 \(O(N \log N)\) 解法。对于一个区间的结束位置 \(r\),维护 \(1 \sim r\) 的线性基,而且它是由最靠后的这些数字构造出来的。具体地,每次插入 \(a_r\) 时,从大到小枚举有 \(1\) 的每一位:如果该位为空,插入并退出;否则,选择位置靠后的数字放入,剩下的数字消掉这一位后继续往前循环。
为什么要这么维护呢?对于一个有端点 \(=r\) 的询问,取线性基里所有位置 \(\geq l\) 的数字出来,即是关于它的线性基。基于此直接询问即可。
ECR#58F
题意:有 \(N(\leq 400)\) 个城市,第 \(i\) 个城市位于 \(a_i(\leq 10^9)\) 公里处。 有 \(M(\leq 250000)\) 辆卡车在运输,第 \(i\) 辆车要从城市 \(s_i\) 到 \(t_i\),每公里耗油 \(c_i\),且最多能在沿途经过的城市加油 \(k_i\) 次(每次加满)。设计一个全局卡车的最小油箱容量使得所有限制都被满足。
题解:一种直观的想法是二分答案,然后就掉进死胡同了……其实可以直接算出每个卡车的最小要求取个 max 的。
因为 \(N\) 比较小,考虑对城市进行 DP。限制很多,而且 \(c_i\) 彼此不一样,所以要把和路程有关的量放在 dp 数组的值里。枚举每一个起点 \(s\),设 \(dp_{i,j}\) 表示从 \(s\) 到 \(i\),最多能加 \(j\) 次油的情况下,最小的可行油箱容量。该 DP 可以通过单调性 \(O(N^2)\) 预处理出。然后跑一遍相同起点的限制算一算即可,总复杂度 \(O(N(N^2+M))\)。
ECR#58G
题意:给出 \(N(\leq 2 \times 10^5)\) 个数。将它们划成一些连续的段,每一段的值为这一段数字的异或和。对于一种划分方案,如果不存在异或和为 \(0\) 的段的集合,则称之为合法划分。求合法划分最多能划成几段。
题解:显然是线性基相关的题。一个很重要的发现是,每个段自身的异或和 \(xor_1,xor_2,\dots\) 构成的线性空间,等价于前缀异或和 \(sum_1,sum_2,\dots\) 构成的线性空间。\(sum_n\) 必须选,然后就只要从后往前扫描,每次把 \(sum_i\) 丢进去,如果不能消掉,就选上这一段。复杂度 \(O(N \log N)\)。
CR#530C
题意:构造一个 \(N(\leq 10^5)\) 个点、每个点深度之和为 \(S(\leq 10^{10})\) 的树,要求度数最小。
题解:对于固定的 \(N\) 最大度数 \(d\),能构出的树的 \(S\) 是一段连续的区间。所以我们可以直接确定出最小度数 \(d\)。构造的时候,我采用逐层构造。在每一层,放了(确定了)若干个点后,剩下能构造出的 \(S\) 也是一段连续的区间,而且这些区间是有单调性的。所以每次二分放多少个点,继续往下构造即可。
CR#530D
题意: 每次选择两个数 \((a,b)(a \leq b)\) 合并成 \(a+b\),这样 \(N\) 个数合并 \(N-1\) 次后就只剩下一个数了。合并过程中,每出现 \(b \leq 2a\) 的情况,不确定值就加一。现在有 \(T(\leq 5 \times 10^5)\) 个操作,每次加入一个数或者删除一个数,或者问当前数字集合的所有合并方案中,不确定值之和最大可能是多少。
题解:比较传统的套路题?不加证明地猜想,每次挑最小的两个数合并会使得不确定值之和最大。但是哈夫曼树是不能动态维护的。手画一些例子发现很难出现 \(b > 2a\) 的情况。将原数组排序后,显然 \(2\sum \limits_{i=1}^{k-1} a_i < a_k\) 是 \(b > 2a\) 的充分条件;其实这也是必要条件。考虑直接用权值线段树来维护这些操作。每次暴力累加一段前缀的和 \(x\),然后线段树里寻找第一个大于等于 \(2x+1\) 的数。每次至少扩大两倍,总复杂度 \(O(N \log^2 N)\)。
Hello 2019 D
题意: 黑板上写了一个数 \(N(\leq 10^15)\),操作 \(K(\leq 10000)\) 次,每次将其等概率变成它的一个因数。问最后留在黑板上的数的期望。
题解: 很old的题了。一个显然但是重要的结论是:各质因子之间独立。每个质因子计算时只要考虑质数就行。对于每一个质因子直接 \(O(Kc)\) DP即可,总复杂度就是 \(O(K \log N)\)。也可以一开始全都预处理好,设 \(f_{i,u,v}\) 表示 \(u\) 经过 \(i\) 轮到了 \(v\) 的概率,可以用前缀和优化成 \(O(K \log^2 N)\)。
Hello 2019 F
题意:维护 \(N(\leq 10^5)\) 个可重集,一共有 \(Q(10^6)\) 个操作。①将第 \(i\) 个可重集设置为只有一个元素 \(v\) 的集合。②将第 \(i\) 个集合设置为第 \(j\) 个和第 \(k\) 个的并。③将第 \(i\) 个集合设置为第 \(j\) 个和第 \(k\) 个的乘。定义乘操作为:\(\forall x \in S_j,\forall y \in S_k,(x,y) \in S_i\)。④询问元素 \(v\) 在第 \(i\) 个集合里出现了奇数次还是偶数次。 \(v \leq 7000\)。
题解:一看数据范围就是 \(bitset\) 乱搞的题。因为是问奇偶性,容易发现,只要维护可重集里每个数是否出现了奇数次。③ 操作看起来十分难维护。从集合反演那套理论中获得启发,尝试将集合转化成“另一种形式”来维护。gcd和因数有很大的关联,对于①操作,考虑将所有 \(v\) 的因数标为 \(1\),观察是否能维护;即,用 \(F_x=\sum \limits_{x|y} S_y\) 来表示集合 \(S\)。惊奇地发现,③ 操作可以直接用 \(F_x \cap F_y\) 来快速维护。而 ② 操作依然是简单的 \(\oplus\) 操作。至于询问的话,可以直接预处理莫比乌斯函数,也表示成 \(bitset\) 形式,就可以做到快速询问了。总复杂度 \(O(\frac{QV}{32})\)。
Hello 2019 G
题意:给出一个 \(N(\leq 10^5)\) 个点的树,一共有 \(2^N\) 种点集选取方案。设 \(f(S)\) 为,在树上将点集 \(S\) 连起来需要用到的边的数量。求 \(\sum f(S)^K\)。\(K \leq 200\)。
题解:先考虑暴力 DP,用一个长度为 \(K+1\) 的数组,来维护当前所有方案的 \(0,1,\dots,K\) 次方的和。在原树上 \(DP\),设 \(f_{x}\) 表示 \(x\) 子树里至少选择一个点的方案数组。为什么要至少选一个点呢?这样就要强制往上连边了。对于一种点集选取方案,在它们的 \(LCA\) 处统计答案。很容易设计出一个 \(O(NK^2)\) 的做法(会出现两个方案数组关于组合数卷积的操作)。
这种 \(K\) 次方的题,肯定是用第二类斯特林数优化。尝试将方案数组的结构改一改。本来的意义是:第 \(i\) 个数是所有方案的 \(i\) 次方之和;现在的意义是:第 \(i\) 个数是 \(\sum C_{x}^(i)\)(\(x\) 是所有方案的值)。一般斯特林数优化的题只会出现答案整体加一的情况,这样新的方案数组可以类似于组合数的转移,复杂度从 \(O(K^2)\) 降为 \(O(K)\)。
但此题中,会出现两组答案合并(左右两个集合里的方案两两组合构成新的答案)的情况。一般的,我们有: \(\sum \limits_{u} \sum \limits_{v} C_{u+v}^k=\sum \limits_{i=0}^k [\sum \limits_{u} C_u^i] \times [\sum \limits_{v} C_v^{k-i}]\) (考虑组合数实际意义即可证明)。所以依然可以用卷积的方式来合并。
问题是:现在的合并复杂度依然是 \(O(K^2)\) !注意到本题是在树上做,是有特殊性质的。对于一个子树大小为 \(size_x(size_x \leq K)\) 的子树,它内部点集无论怎么选,边最多 \(size_x-1\) 条,所以方案数组 \(\geq size_x\) 的位置必然是 \(0\)。我们可以用树形背包的经典 \(trick\),每次只 \(for\) 到 \(\min(size_x,K)\),复杂度就能变成 \(O(NK)\)。