• COCI 2021/2022 题解


    看了下赛程,大概只能打 Round 1 和 Round 2 了,之后可能就退役了。

    Contest #1

    打的时候因为有点事,大概只打了一个多小时。现在终于有时间补完了。

    题对于知识点完备的选手比较简单。我显然不是这样的选手,做做就当学点东西了。

    C、D、E 题代码可以翻 LOJ,其他三题有需要可以联系我。

    A - Ljeto

    直接模拟即可。

    B - Kamenčići

    博弈题。(nle 350),比较小,可以考虑一个大概不超过 (O(n^3)) 的 dp。

    考虑一个状态有三个要素:左右端点和,以及共取了多少个红色石子(只需要记录一个人的,因为另一个以及可以据此确定)。

    那么定义:(f(l, r, c)) 表示当前操作者面对的局面是,之前以及取过 (c) 个红石子,现在剩下了区间 ([l,r]),是否有必胜策略。

    根据必胜必败态定理得到转移:(f(l, r, c) = lnot f(l+1,r, c') lor lnot f(l,r,c'))(c') 是计算得到的对方取过的红石子数。

    复杂度 (O(n^3))。据说可以分析性质得到 (O(n^2)) 解法,可以到 cf 看看。

    C - Logičari

    第一次写基环树题!做法可能不是最简洁的。

    题意简述:对基环树黑白染色,要求每个点相邻恰好一个黑点。求最小可能黑点数。

    先转化为正常的树:任意找一条环边 ((a, b)) 断开,然后钦定一下断开的边两端的四种颜色组合。

    不妨设 (a) 为根,每个点四个状态,记录自己和父亲的颜色选择。然后做正常的树形 dp。

    但是 (a, b)​ 两个点需要是特殊处理的。对于 (a),可以试做它的父亲为 (b)。而对于 (b) 需要额外讨论一下……具体细节就不展开了。

    复杂度 (O(n))

    D - Set

    一下所有数字默认减一(({1, 2, 3} o {0, 1, 2}))。

    我们挖掘一下题目的性质:对于一个位的三个数字 ((a,b,c)),其所有合法组合对应的数字加起来都是三的倍数,即 ((a+b+c)mod 3 = 0)

    考虑到本质不同三元组个数为 (3^m)​,设 (f[i]) 表示 (i) 三进制表示对应的 (m) 元组的个数((f[i]in {0, 1}))。

    题目要求选取的三个 (m) 元组 (i,j,k) 的每一位都满足三进制不进位加法((oplus_3))为 (0),那么就是 (ioplus_3 j oplus_3 k = 0)

    考虑卷积,下标用上面的 (oplus_3),那么最后 (f) 自己卷自己三次后 (f'[0]) 就是答案。可以用 3 进制 FWT 实现。

    E - Volontiranje

    有一个传统的流做法,但是应该只能跑 subtask 2。

    考虑一个基于贪心的神奇结论:在所有备选 LIS 中,抽出一个反转后字典序最小的必然不劣。

    首先感性理解比较真,意识流 证一下也不难:考虑有两组 LIS:({i_1,i_2, cdots,i_k}, {j_1,j_2, cdots,j_k})​​​​​​,那么我们对应项小的换到 (i)​​​​​​,大的换到 (j)​​​​​​,即用 ({min(i_1, j_1),min(i_2, j_2), cdots,min(i_k, j_k)}, {max(i_1, j_1),max(i_2, j_2), cdots,max(i_k, j_k)})​​​​​​​ 取代之,不难发现其仍然合法。这个方法可以对一个解集在解之间做调整。但是如果最小的那个本身不被该解集包含,则我们可以不要这个解集,而必然存在另一个“可以向小调整”的解集。(看我题解很难没有疑问(草),想要靠谱点的可以看 cf 或翻官方题解)

    然后尝试实现。直接一次 (O(n))​​ 扫一组解必然不对,考虑先做一次 dp 跑出每个位置结尾的 LIS,然后按 dp 值将下标分组。显然的,同一组的按位置升序排好之后,其值必然递减。

    那么,如果现在需要选 dp 值为 (i) 的组中的位置,上一次选了位置 (x)。我们先删去在 (x)​ 之后的元素:易知这些元素在本次不可用,之后也不会起作用。

    删掉一些后,查看最后面的位置 (y) ,是否可以接上 (x)。如果 (a_y > a_x),那么 (x) 就没办法用了。需要注意,这不意味着求解结束,而只是将 (x) 删去,(y) 可能在枚举字典序更大的一组解是被使用。因此使用搜索回溯实现。

    每个位置用一次就会被删除,搜索部分复杂度 (O(n))。总复杂度 (O(nlog n))

    Contest #2

    D、E 等 upsolve 出来再补了。

    A - Kaučuk

    签到

    B - Kutije

    首先转化题意,将给定的 (p_i) 转化为图上的 (i o p_i) 的有向边。然后每个询问相当于问是否存在 (u)(v) 的有向路径。

    观察到 (nle 1000),我们可以考虑预处理所有的答案。但这张图是稠密图,连做 (n) 次 DFS 的复杂度是 (O(n^3))。不过我们发现一次 DFS 每个点之后访问一次,但主要的时间消耗在于找到第一个没有访问过的相邻点。

    于是不难想到用 bitset 加速寻找,复杂度 (O(n^3/w))

    C - Hiperkocka

    构造垃圾终于瞎搓成功了!

    首先为了让结构更清晰,我们将这些边分为 (n)​ 层,根据第 (k)​ 位不同产生的边放在第 (k) 层,每层有 (2^{n-1})​ 条边。

    根据直觉,我们想办法让这 (n) 条边的树的每一条都用掉一层的一条边,这样恰好每层用 (2^{n-1}) 次。

    第一棵树是很好构造的,直接从位置 (0)​ 开始 DFS,每次 (O(n)) 遍历最小未使用的层。然后我们发现如果从 (1) 直接开始 DFS 构造第二棵树就可能冲突,不过根据观察,我们要避开的话,最好是从 (3)​ 开始。

    这时你可能发现了,位置 (0)(3) 除了上面几层用的边,其余都是对称的。这启发我们倍增地构造一组靠谱的起始点,使得直接在这些位置 DFS 就能出解(并不会证为什么可以这样,这里如果有人会证可以发个评论)。

    考虑从 ([0, 4) o [4, 8))​,如果同样用对应的位置 (4,7)​ 的话会冲突,而反过来用位置 (5, 6)​ 的话则恰好错开,同时 (5, 6)​ 构造出的树也是在低层对称的,同 (0,3)​ 一样也不会冲突。

    那么不妨尝试如下算法:初始区间 ([0,2))(0)​ 为起始点,然后复制一份,将是否为起始点状态取反,接在后面。

    然后对于每个起始点都搜出一棵即可。

    D - Magneti

    E - Osumnjičeni

    草,赛后发现是 sb 题,但是 C 题搞太久了……

    口胡,不知道对不对。

    考虑答案的计算方法是确定的:对于询问 ([l,r]),我们从 (l) 开始,找到一个最大的 (ile r),满足 (lsim i) 号身高区间全部不交。那么下一次从 (i+1) 开始重复操作即可。最后答案就是操作的轮数(可能反过来再做一次)。

    第一是预处理右侧最远的合法位置。考虑建立以身高(离散化)为下标的线段树,从 (1) 扫到 (n)。每次查询当前身高区间中的最大值,然后在这个区间做区间赋值。

    第二是快速跳转。不难发现这个可以倍增加速。

    最后复杂度 (O(nlog n))

    本文来自博客园,作者:-Wallace-,转载请注明原文链接:https://www.cnblogs.com/-Wallace-/p/sol-coci2021-2022.html

  • 相关阅读:
    MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录3
    19c上ADG主库sys密码修改会影响备库同步吗?
    MySQL中sql_mode的设置
    [自制工具]批量后台更新统计信息
    openssl加解密实战
    [自制工具]简便易用的ADDM报告生成工具
    MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录2
    MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录1
    Windows11如何设置经典的右键菜单
    MVC3过滤器实现多语言
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/sol-coci2021-2022.html
Copyright © 2020-2023  润新知