Grakn Forces 2020 题解

A

直接从左到右确定即可,因为每个位置有 3 个不同选择,但是相关的限制只有 2 个,所以必然有解。

\(\Theta(n)\)

B

\(cnt = a\) 序列中不同的数的个数。

不难发现如果确定了 \(m\) , 那么 \(cnt \leq m * (k-1) + 1\) 的数列都能被表示出来。

至于证明,考虑一下差分数组即可。

每一个 \(b_i\) 都可以使差分数组上的 \(k-1\) 个位置有值,那么就可以表示出有不超过 $ m * (k-1) + 1$ 个不同数字的 \(a_i\) 了。

最后特判一下 \(-1\) 即可。

\(\Theta(n)\)

C

对每个点计算左边的车到达这个点的时间,以及右边的车到达这个点的时间,然后找到两辆车相遇的位置即可。

\(\Theta(n)\)

D

记坐标整体右移的距离为 \(X\) , 整体上移的距离为 \(Y\) .

枚举每一对点 \((a,b)\) \((c,d)\) , 它给答案的贡献就是对于一段 \(X\) 的前缀 , \(Y\) 必须 \(\geq\) 一个值的限制。

对限制做个后缀 \(max\) 即可。

\(\Theta(nm+max(a_i,b_i,c_i,d_i))\)

E

删掉的权值最小,考虑转化为保留的权值最大。

把集合和数字都看成点,集合里有数字就把这个数字往集合连边,求最大生成树即可。

不难发现这个最大生成树的权值可以达到,并且如果出现环,那么必然会有 \(rainbow\) \(cycle\) .

证明 : 如果这张图上存在环,那么我们考虑一个环

\(x->S_1->y->S_2->z \cdots -> x\)

如果这上面有相同的集合,那么就把它们缩起来,这个环显然还是存在的,并且因为有环,所以我们在缩边的时候一定能保证环内仍然有 \(\geq 2\) 个不同的集合.

\(Kruskal\) 即可。

\(\Theta((n+m)\log (n+m))\)

F

难写的做法

一开始 \(n\) 个数互不相等,我们把这个局面记为 \(n\) 个大小为 \(1\) 的下标集合。

不难发现,我们可以做以下两种操作:

1、花费 \(n\) 次操作的代价,把两个大小为 \(n\) 的集合合并为一个大小为 \(2n\) 的集合,这个下标集合内所有下标对应的数仍然是全相等的。

2、花费 \(0\) 次操作,分裂两个下标集合。

那我们只需要合并到最后只有两个集合即可。

考虑二进制合并,然后剩下 \(\Theta(\log n)\) 个集合,其中最大的集合大小大于 \(n\) 的一半。

然后利用最大的集合,把其它集合一一合并起来,这样就只剩两个集合了。

实际测试中对于 \(n = 15000\) 的情况只需要 \(100068\) 次操作 。


好写的做法

还有一种做法,先求出 \(k\) 满足 \(2^{k+1} \geq n\) , 然后直接做两次,先使前 \(2^k\) 个数变为相等的,再让后 \(2^k\) 个数变为相等的即可,操作数比我当场写的做法多一点,但是很好写。

G

一些怨念:当时差 2min 没冲完这个题……

建出 \(Kruskal\) 重构树. 不难发现我们取的联通块必然是 \(Kruskal\) 重构树上的一个子树。

那么 \(check\) 每个子树能否成为一个联通块,然后做一个树上背包即可。

H

\(0\) 的个数为 \(cntz\) , 不难发现答案有一个上界为 \(\lfloor \frac{cntz}{2}\rfloor\) .

考虑把序列分为两个部分, \(L\)\(R\) , 满足 \(L\) 部分中的点右边都有 \(\geq \lfloor \frac{cntz}{2}\rfloor\)\(0\) , 而 \(R\) 部分中的点左边都有 \(\geq \lfloor \frac{cntz}{2}\rfloor\)\(0\) , 那么 \(L\) 部分只需要考虑在左边的匹配, \(R\) 部分只需要考虑在右边的匹配即可 , 最后答案需要对 \(\geq \lfloor \frac{cntz}{2}\rfloor\)\(\min\) .

不难发现,对于每个权值只需要在 \(L\) 中保留其最靠右的点 \(l_x\) , 在 \(R\) 中只需要保留其最靠左的点 \(r_x\) .

不难构造出一个网络流模型 :

S -> 权值 , 权值 -> \(l_x\) , 权值 -> \(r_x\) , \(a_i = 0\)\(i\) -> T. 这些边权值为 1

\(L\) 内部 \(i+1\) -> \(i\) , \(R\) 内部 \(i\) -> \(i+1\) , 这些边权值为 INF

答案即为这个网络流图的最大流。

最大流 = 最小割 , 考虑计算最小割。

不难发现,割掉的边一定是一些 S -> 颜色 和 0 的一段在 \(L\) 中的前缀 、 一段在 \(R\) 中的后缀。

枚举割掉的 0 的在 \(L\) 中的前缀的长度,然后用线段树维护对于每个 \(R\) 中的后缀的答案即可。

\(\Theta(n\log n)\)

I

考虑观察数列 \(x \oplus (x-1)\) , \((x-1) \oplus (x-2)\) \(\cdots\) \((x-k+1) \oplus (x-k)\) .

可以发现如果对 \(x\) 这个数进行了 \(k'\) 次减少操作 , 那么就是把整体的异或异或了 \(x\) 所对应的数列的长度为 \(k'\) 的前缀。

考虑事先异或上所有 \(a_i\) 的异或和,那么问题可以转化为 : 对于每个 \(x\) , 只能取它对应的数列\(x \oplus (x-1)\) , \((x-1) \oplus (x-2)\) \(\cdots\) \((x-k+1) \oplus (x-k)\) .的一段前缀,求取出来的部分的异或和为 \(0 \cdots 2^c\) 的方案数。

不难发现数列 \(x \oplus (x-1)\) , \((x-1) \oplus (x-2)\) \(\cdots\) \((x-k+1) \oplus (x-k)\) 中的数都是形如 \(2^d - 1\) 的形式,记 \(Logk = \lceil \log_2{k}\rceil\) , 这个数列对于任意的 \(x\) ,都最多只有一个 \(2^d-1\) 中的 \(d > Logk\) .

把完全相同的数列合并到一起,不同的数列一共只有 \(192\) 种。

对于这 \(192\) 种数列进行 DP 预处理,具体是记 \(f_{0/1,v,i,now}\) 为当前决策到第 \(i\) 位,前 \(i\) 位被选中的数有 \(now\) 个,当前异或出来的结果低于 \(2^{Logk}\) 的位置为 \(v\) , 高于 \(2^{Logk}\) 的位置是否有值, \(0/1,v\) 可以唯一确定异或出来的数。

然后把所有的 DP 预处理出来的结果 FWT 合并即可。

如果先多项式 \(\ln\) 再用加法来实现这个合并的过程,可以达到一个很优秀的复杂度,参见 EI的提交 , 最慢的点只跑了 93ms .

posted @ 2020-10-01 19:18  srf  阅读(384)  评论(0编辑  收藏  举报