zoukankan      html  css  js  c++  java
  • NWERC 2020 题解

    和主席 VP 玩了一下,打了 8 题,只能说主席太强了。

    比意想中的要简单一点,而且有两道随机化题。

    A - Atomic Energy

    考虑一个暴力 dp:设 (f(i)) 表示中子数为 (i) 的原子可以产生的最小能量。那么在 (M) 以内的 dp 值是可以 (O(M^2)) 预处理的。

    注意到 (k) 很大,而 (n)​ 很小。考虑背包问题的一个假贪心:每次选“性价比”小的。一般情况下,组合起来可能不是最优的。然而当我们的容量很大时,我们可以在一个限度内施展这样的贪心。由于每个物品的体积都比较小,所以“组合更优”不会在大范围出现。

    对于本题,设阈值 (M=n^2)(这个值不一定最优,是平方算法可以承受的较大值)。然后 (O(M^2)) 预处理小范围的 dp,对于 (k) 很大的情况可以先一直一个性价比最小的,直到在 (M) 以内直接拼上 dp 值。这样复杂度是 (O(M^2+q)) 的。

    C - Contest Struggles

    签到。答案为 ((d imes n - k imes s) div (n-k))​。在 ([0,100]) 内合法。

    D - Dragon Balls

    限制很宽,有很多种做法。

    这里是个好写的做法:考虑随机一个点,算出距离 (d^2)。考虑这个 (d^2) 肯定是根据勾股定理算出来的,那么我们只要得到 (a,b) 两个整数满足 (a^2+b^2=d^2),然后在随机的那个点周围 (8) 个方向上都测一遍。

    实测这样得到的 ((a,b)) 最多三十多组,并且随机情况组数很少。所以一千次是绝对足够的。

    (d^2) 可以达到 (10^{12}) 级别,但 (a, b) 只有 (10^6)​ 级别,所以不会有超时问题。

    E - Endgame

    首先考虑一个简单问题:给定始终点 (A, B),判断 (A) 能否操作两次吃掉 (B)。这个比较简单,用一个 set 记录所有操作,然后枚举第一次操作,尝试配对所求第二次操作。这样可以 (O(nlog n)) 完成一次判断。当然可以强行优化到更快。

    实现上面从操作之后可以判断 Alice 是否能赢。但是之后是否存在 tie 的位置似乎没什么好办法,对于 (n) 比较小我们可以逐一测试,但是肯定是过不了的。

    我们发现一个很离谱的事情就是,棋盘是 (n imes n) 的,而操作种类是 (n) 个。为什么都是 (n)(n) 个操作可以拼出 (O(n^2))​ 个位置,但绝(除了 (n=2,3) 的小数据)不会占满整个棋盘,而且冷静分析有相当一部分位置都是空的。

    我们考虑随机化:每次随机一个点,判断是否可以 tie。由于随机很多次都点不到的概率是极低的,所以很快就能找到解。

    官方题解指出空位的规模是 (n^2/2),因此期望两次出解。但是我不知道怎么来的,一个较简单的 (n^2/4) 的构造是 ((1, 0), (2, 0), cdots, (n/2, 0), (0, 1), (0, 2), cdots, (0, n/2))

    F - Flight Collision

    要求快速模拟整个过程,实际上只需要我们正确模拟就行了,因为每个坠毁时间只会在一对飞机上发生一次。

    要正确模拟,只要让一个个坠毁事件按时间顺序发生,显然这样不会出现任何跨越的情况,其间飞机间的相对位置也不会改变。

    考虑用 set 或链表维护存活的飞机,用堆维护接下来可能发生的坠毁事件。复杂度 (O(nlog n))

    G - Great Expectations

    完全不会这种带环的期望题。

    从容错的角度考虑状态设计:我们需要比 (r) 小,而 (n) 是不得不消耗的花费,那么最多可以承受 (r-n-1) 的失误代价和。设 (f(i,j)) 表示将要到达第 (i) 个关卡,以及消耗了 (j) 的容错,走到终点需要的期望时间。

    可以发现的是,如果真的要重开,那一定是刚刚失误被卡了一下的那个时刻。那么有方程:

    [egin{aligned} f(i,j) & leftarrow (f(i+1, j) + t_{i+1}-t_i) & imes p_i \ f(i,j) & leftarrow min(f(i+1, j) + t_{i+1}-t_i + d_i, f(0, 0)) & imes (1-p_i) \ end{aligned} ]

    其中 (f(0,0)) 是起点的期望,代表重开,同时也是我们要求的答案。

    我们试一个答案 (v)​​,并在方程中用 (v)​​ 代替 (f(0,0))​​ 计算,并用最后得到的 (f(0,0))​​ 比较。如果 (f(0,0))​​ 较大说明答案会比 (v)​​ 更大,反之同理。我也不知道为什么会这样。

    最后二分答案即可。复杂度 (O((r-n)m log ext{ans}))

    H - Hot Springs

    把所有数组放到一个数轴上。可以发现,我们从中间位置开始,左右横跳,越跳越远,这样必然可行。

    那么我们找到中位数,然后分成两部分,轮流输出即可。

    I - Island Tour

    考虑 (O(n^4)) 暴力,枚举三个人的位置 (i, j, k),然后检查每个位置是否都不冲突。如果 (i, j) 两个人中 (j) 先到某位置 (p),那么 (j) 离开 (p) 的时间不应大于 (i) 到达 (p) 的时间。

    VP 时主席写了个这样的暴力,然后加了个超过时限就输出无解摆烂,结果真的 AC 了。之后猜了猜,如果有解,那么 (i=1) 时也必然有解,结果加个 assert 也过了。这玩意也不知道怎么证,也可能是假的。如果有人能给个证明可以在 这里 或者评论区说两句。

    但其实靠谱做法非常简单:观察到我们要判的只有 (O(n^2)) 种本质不同的位置对,那么只有 (O(n^3)) 预处理是否合法即可。最后求解也是 (O(n^3))

    J - Joint Excavation

    很好玩的题。官方解法也非常妙。

    考虑直接 DFS。DFS 过程中的点我们分为三类:(一)从未访问的点,(二)DFS 栈中的点,以及(三)曾经访问过但不在栈中的点。曾经访问过就是经历过回溯操作的点。

    一个神奇的观察:三类点中,(一)类和(三)类间不相邻。具体证明非常显然:考虑 DFS 的过程,如果存在这条边,那么当时不可能直接回溯而会直接进入那个未访问的点。

    注意(二)类点刚好可以构成一条点不自交的路径,那么最后在 DFS 中某时刻出现(一)类点和(三)类点数目相同时遍求得了一组解。

    K - Keyboardd

    检查所有小写字母及空格,把多的输出即可。

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

  • 相关阅读:
    3747 [POI2015]Kinoman
    1303 [CQOI2009]中位数图
    3769 [spoj 8549] BST again
    1015 [JSOI2008]星球大战starwar
    1193 [HNOI2006]马步距离
    合并Git仓库不相关历史版本解决方案
    vue-cli项目实现动态锚点定位
    jQuery加css3实现菜单栏组件(可无限添加子列表)
    JavaScript文件转成base64编码
    Ajax获取服务器响应头部信息
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/sol-nwerc2020.html
Copyright © 2011-2022 走看看