Solution Set #9
在 cdqz 的集训结束了,虽然总榜比较好看但感觉只过了一堆平凡题。
怎么一个月就省选了(恼)
upd:更得好像有点少,下周的直接往里面加算了。
150【IOI2016】shortcut(拆绝对值)
考虑确定了架桥架在哪里之后怎么算(经过桥的)直径。实际上就是 \(\max (|pos_u-pos_x|+|pos_v-pos_y|+d_u+d_v)\)。
大力转切比雪夫(大概)然后二分,先排除 \(|pos_u-pos_v|+d_u+d_v\leq X\) 的点,剩下的点限制 \(pos_x-pos_y\) 和 \(pos_x+pos_y\) 的范围,然后双指针就行。
提交记录 #674333 - Universal Online Judge (uoj.ac)
151【IOI2016】messy(交互,分治,构造)
考虑一个构造:传一个 \(s_0=1\),然后询问 \(n\) 次,就可以知道 \(0\) 的位置。
实际上你也可以传一个集合过去,在 \(n\) 次询问得到这些集合。
问题是每个数只能传一次。所以假设我们上次传过去的集合是 \(S\),那么传下一个集合 \(T\) 的方式是把 \(x\in T\),\(\{x\}\oplus S\) 传过去。由于我们知道 \(S'\),所以枚举 \(x'\) 之后询问 \(\{x'\}\oplus S'\) 很容易得到 \(T'\)。
大力二进制分组,可以得到 \(n\log n\) 次操作的做法。
提交记录 #674659 - Universal Online Judge (uoj.ac)
152【IOI2017】Ancient Books(贪心,析合树)
考虑 \(\text{cir}(p)=1\) 的情况,发现答案是下界 \(X=\sum |i-p_i|\)。
容易构造出 \(2(\text{cir}(p)-1)+X\) 的上界:搜出生成树,每次以 \(1\) 的代价换连通块,然后以 \(1\) 的代价回到原来的位置。
然而换块未必需要 \(1\) 的代价。考虑连通块编号为 \(\{1,2,1\}\) 的三个点,可以从第一个数出发往后走到 \(2\),把书放到 \(2\),做完 \(2\) 连通块,再返回原位置。随便构造一下可以发现一个值域连续段(\(p_{[l,r]}\to[l,r]\))可以取到下界 \(X\),所以换块次数是值域连续段数量 \(-1\)。
写上去发现只过了 \(s=0\),发现 \(s=1\),\(\{0,2,1,4\}\) 会出问题,也就是 \(s\) 需要”跳出来“。然后大概是析合树上跳祖先的过程(?)直接贪心就好了。
不太懂析合树,瞎写了个东西/kk。
提交记录 #674659 - Universal Online Judge (uoj.ac)
153 IOI 2017 Toy Train(博弈,图论)
考虑只有一个充电站,且充电站是自环怎么做。可以 BFS 出所有 Arezon 能保证到充电站的结点。
考虑只有一个充电站怎么做,按上面 BFS 之后,如果 Arezon 控制充电站且存在出边对应结点能到充电站,或者 Borzon 控制且全部出边都能到充电站,那么能到的就是合法的,否则答案为空集。
考虑多个充电站,那么 BFS 多次,如果一个充电站不满足上面条件那么一定不会去这个充电站充电,那么把这个充电站删掉,重复 \(n\) 次可以得到解。
提交记录 #674949 - Universal Online Judge (uoj.ac)
154 IOI 2017 Simurgh(交互)
可以 \(\mathcal{O}(m)\)。具体而言,找到生成树,然后对于一个环,依次删去一条树边并加入非树边,可以得到非树边和树边的大小关系。如果所有边都和非树边相等那么一定都是 \(0\)。据此可以得到所有边的信息。
拓展到正解:如果我们只询问生成树上边的信息,那么我们就可以选择一个无环的边的子集,并询问子集中是否有关键边,然后通过二分技巧找到所有关键边。关键在于把原图拆成尽可能少的生成森林,一个构造是:找到一个点和它相连的所有边,这样可以拆出来 \(\mathcal{O}(n)\) 棵生成树,在所有生成树里面二分边即可。询问次数大约是 \(3n+n\log n\),不是很懂为啥给 \(8000\) 次询问。
https://uoj.ac/submission/675475
155 CTT2019 匹配问题
考虑钦定了选 \(l_b\) 的集合 \(S\) 之后怎么判断。一个算法是倒着贪心,每次选最远的点。但是没啥前途。
考虑利用 Hall 定理判断。可以得到 \(\mathcal{O}(n^2)\) 组限制:对于 \([i,j]\),假设 \(N(S)\) 对应的区间是 \([a_i,a_j+l_a(l_b)]\) 中的所有点,那么我们需要保证 \(|\{k|k\in[i,j],a_k+l_a(l_b)\leq a_j+l_a(l_b)\}|\leq N(S)\)。可以简化为:找到满足 \(a_k+l_b\leq a_j+l_a(l_b)\land a_k+l_a>a_j+l_a(l_b)\) 的区间 \(k\in[l,r]\),限制相当于 \([l,r]\) 不能选择超过 \(c\) 个数。
利用这 \(\mathcal{O}(n^2)\) 组限制,贪心选,可以得到一个 \(\mathcal{O}(n^2)\) 的算法。
注意到限制中长度大于 \(l_a\) 的区间是平凡的,我们只需要对于每个相同的 \([l,r]\) 找到 \(c\) 的最小值,可以观察到这样的 \([l,r]\) 只有 \(\mathcal{O}(n)\) 组。对于剩下的限制,条件相当于只保留选择 \(l_b\) 的点之后,存在完美匹配。
对于这类限制,\(l_a=5\times 10^5\) 的情况可以直接贪心,加上 \(l_a\) 的限制之后也是一样的。使用数据结构维护,复杂度 \(\mathcal{O}(n\log n)\)。
https://qoj.ac/submission/317897
156 qoj5017. 相等树链
对第一棵树点分治转化问题。
关键在于:如何找到一个条件判断跨过分治中心的路径 \(u\to root\to v\) 是否在第二棵树上仍然是链。将第二棵树的根设为 \(root\)。考虑对于路径上的结点 \(w\),\(w\) 在第二棵树上被包含在链里,需要 \(fa_w\) 也被包含在链里。基于 \(w\) 构成的集合和 \(fa_w\) 构成的集合可以给出一个构造:记 \(S\) 为 \(w\) 删去 \(u,v\) 的集合,\(T\) 为 \(fa_w\) 删去 \(root\) 的集合,则 \(S=T\)。
此时条件转化为集合相等的形式,可以利用 xor-hashing 的技巧给出进一步转化。那么枚举第二棵树中的其中一条链,计数另一条链的方案数,那么我们需要枚举删去的直径端点,求出 \(S\) 部分的哈希值和 \(T\) 部分的哈希值。还需要另外满足的条件是:然而这样会出问题,可能我们删去了 \(3\) 个结点,所以需要增加条件:删去的端点数要恰好等于 \(fa_w=root\) 的 \(s\) 的个数,且个数不超过 \(2\)。使用哈希表统计,复杂度 \(\mathcal{O}(n\log n)\)。
https://qoj.ac/submission/318292
157 qoj5016. Range Minimum Element
和 AGC056B 一样,构造一个填数方式和 \(b\) 序列的映射,从小往大考虑,每次填一个最小值,并将包含这个最小值的所有区间计入答案,之后将整个序列割成两部分处理。
为了保证是一一映射,我们钦定当前填的最小值是所有可能的最小值位置中最靠前的。也就是说,假设我们根据 \(b\) 得到了 \(a_i\geq x_i\) 的下界,那么我们找到 \(x_i=mn\) 且 \(i\) 最小的位置,并令 \(a_i\gets mn\)。
假设 \(S_i\) 为包含 \(i\) 的区间集合。稍加思考可以发现 \(i\) 的合法条件是 \(i\) 左侧不存在 \(j\),使得 \(S_j\neq \varnothing\land S_j\subseteq S_i\),关键在于判断集合包含的方法。注意到 \(S_j\subseteq S_i\) 当且仅当不存在区间包含 \(j\) 且不包含 \(i\),可以看做一个二维数点问题,利用差分维护即可。
还有 \(c\) 的问题。我们先计算 \(c=1\sim n\) 的答案,利用二项式反演算出恰好有 \(i\) 个元素的答案,然后乘个组合数系数累加进答案。官方题解利用的是插值。
https://qoj.ac/submission/318493
因为以为条件是集合相等所以代码中包含了神秘 xor-hashing。
158 loj4039. 「SNOI2024」矩阵
注意到一次旋转之后,不在矩形边界上的点四个方向相邻的点是不变的,但是顺序会旋转 90 度。考虑维护一个十字链表。
问题在于如何维护旋转,那么对每个数再维护一个值 \(d\) 表示旋转的次数,一次操作会把矩形中所有点的 \(d\) 增加 \(1\),考虑差分,维护一个位置和它相邻四个位置 \(d\) 的差值,差分信息同样只会变化 \(\mathcal{O}(n)\) 个位置。
矩形加同理,仍然考虑差分即可。
159 loj7905. Ticket to Ride
问题和如下问题等价:
取出序列中不相交的 \(k\) 段,每段贡献为完全包含在区间内的区间权值之和,最大化 \(k\) 段的权值和。
以段数为阶段,每个阶段的转移相当于维护数据结构支持:
- 前缀加。
- 查询前缀 \(\max\)。
注意到前缀 \(\max\) 构成若干段,考虑使用并查集维护这些段,对于一次前缀加,若前缀 \(\max\) 大于下一个比它大的数,那么就合并两端。显然段只会合并,不会分裂。所以复杂度为 \(\mathcal{O}(n\alpha(n))\)。
总复杂度为 \(\mathcal{O}(n^2\alpha(n))\),可以通过。

浙公网安备 33010602011771号