zoukankan      html  css  js  c++  java
  • NOIP2020 部分简要题解

    C

    首先考虑 (n = 2) 怎么做。

    可以发现的是我们一定要借助空柱子 (n + 1),并且两个柱子都必须要移动。

    注意到此时本质上就是将两种球分类,于是我们考虑能否将一个柱子上两种颜色分开(并对其他柱子不产生影响)。

    假设要将 (1) 上两种颜色分开,并且 (1) 颜色在上 (2) 在下。

    (1) 柱子上有 (a)(1) 那么我们考虑现在第 (2) 个柱子上先预留 (a) 个空位,将这些球先全部转移到 (n + 1) 上。

    然后对于第一个柱子上的球从上到下考虑,若当前顶端的球为 (1) 则放到 (2) 柱子上,否则放到 (n + 1) 上。

    然后先将 (n + 1) 上方的 (m - a)(2) 球还原到 (1) 柱子,再将 (2) 上方的 (a)(1) 球还原到 (1) 柱子,最后将 (n + 1) 剩下的球还原到 (2) 柱子。

    容易发现这样对 (2) 柱子没有影响且操作合法达成了目的,仔细定量发现操作数是 (2m + 2a) 的。

    我们对两个柱子都做上面的操作将 (1) 放到上面来,然后就可以轻松达成目标了。

    接下来回到原问题,此时我们发现上述做法的本质是:将柱子 (x) 上颜色为 (c) 的球上提到顶端且 (x) 上其他球相对位置不变,同时不会对其他柱子产生影响。

    此时考虑按照颜色依次还原,假设当前考虑到了颜色 (c) 对上述柱子将 (c) 全部提到顶端,然后将 (c) 移到空柱子上接着任选一个柱子将球全部分配到非满柱子上,就递归为删去这个颜色的子问题。

    分析操作次数,对于每种颜色需要对每个柱子均操作一次,因此操作次数:(sumlimits_{i = 1} ^ n i2m + 2nm = n(n + 3)m),已经可以通过 (70) 分,考虑进一步优化。

    容易发现上述做法操作较多的原因是对 每种颜色 都重新做一轮,这样事实上浪费了很多操作。

    那么能否考虑减少有效颜色的操作呢?考虑分治。

    我们每次考虑将编号 (le mid) 的球染成白色,剩下的球染成黑色,目标同样是将柱子上清成同一种颜色。

    令对于长度为 (n) 的序列操作次数为 (f(n)),那么总操作次数应该为 (f(n) log n),于是只需要考虑上述问题如何做即可。

    类似上提的思路,我们考虑每次任选一个至少有两种颜色的柱子 (x),然后再任选一个 (y e x),在没有完成目标时总能做到。

    (x_0, x_1, y_0, y_1) 分别为 (x) 上白球/黑球数量,(y) 上白球/黑球数量。

    发现总存在 (x_0 + y_0 ge m)(x_1 + y_1 ge m),不妨设 (x_0 + y_0 le m, x_1 + y_1 ge m)

    于此同时,我们不妨设 (x_0 le y_0 le frac{m}{2})

    我们首先对 (x) 将白球上提,消耗次数 (2m + 2x_0)

    然后将 (x) 上的白球全部移动到空柱子上,消耗次数 (x_0)

    (y) 上的球从上到下考虑,若顶端球为白色,那么移动到空柱子上,否则移动到 (x) 上直到 (x) 上球满为止,至多操作 (x_0 + y_0) 次。

    最后将 (n + 1) 上的球全部运回 (y) 上,消耗次数 (x_0 + y_0)

    这样 (x) 上的球全部变为黑色,且因为 (x_0 + y_0 le m) 所以空柱子上球不会爆出来。

    计算上面的总次数:(2m + 5x_0 + 2y_0 le 5.5m),因此我们做到了总操作次数 (5.5nmlog n)

    带入满分的数据范围大约是 (660000) 次,可以轻松通过。

    当然可以底层直接实现 (70) 分的 (n(n + 3)m) 次操作的小常数做法,可能可以达到更优的次数。

    D

    首先考虑一个暴力,先判掉无解的情况。

    注意到题目需要求所有初始局面的存活时间,于是我们类似期望存活时间的转化,令 (f(x)) 为初始位置为 (x_1, x_2, cdots x_m) 的存活时间,那么答案为:

    [sumlimits_t ^ infty sumlimits_x [f(x) ge t] ]

    这等价于令 (f(t)) 表示 (t) 时刻任然存活的初始局面数量,那么答案为:

    [sumlimits_t ^ infty f(t) ]

    此时我们发现,(f(t)) 的数量是每个维度存活数量的积,那么每个维度之间就是相互独立的了。

    注意到有效时间至多只有 (nw) 天,于是可以考虑枚举天数然后暴力维护当天每个维度依然存活的数量,复杂度 (mathcal{O}(nmw))

    考虑优化这个过程,显然问题在于如何优化暴力枚举天数部分。

    (f_i(t)) 为维度 (i) 在时刻 (t) 依然存活的初始状态数量,此时我们有如下关键观察(证明不难):

    • (f_i(t)) 在时刻 (n + 1)(也即第二轮)开始呈周期长度为 (n) 的定值长度减少。

    同时我们可以观察到减少的定值长度为 (q_i = sumlimits_{j = 1} ^ n [c_j = i] imes d_j)

    那么我们令总共经过了 (t) 整轮 后就不存在局面存活了,那么第 (2 sim t) 轮的贡献可以描述为:

    [egin{aligned} sumlimits_{i = 2} ^ t sumlimits_{j = 1} ^ n prodlimits_{k = 1} ^ m f_k(n + j) - q_k imes (i - 2) \ end{aligned} ]

    不妨做简单变换:(t leftarrow t - 2, f_i(n + j) leftarrow f_i(j)),那么上式即:

    [egin{aligned} & sumlimits_i ^ t sumlimits_{j = 1} ^ n left(prodlimits_{k = 1} ^ m f_k(j) - q_k imes i ight) \ &= sumlimits_{i = 1} ^ n sumlimits_j ^ t left(prodlimits_{k = 1} ^ m f_k(i) - q_k imes j ight) end{aligned} ]

    (g_i(j) = prodlimits_{k = 1} ^ m f_k(i) - q_k imes j),容易发现这是一个仅与 (i) 有关的 (m) 次多项式,于是上式等价于求 (n) 个给定的 (m) 次多项式的前缀点值的和。

    有经典结论 (m) 次多项式的非负前缀点值和为一个 (m + 1) 次多项式,于是我们就可以插值得到 (x = t) 处的点值。

    复杂度 (mathcal{O}(nm ^ 2)),瓶颈在于计算 (n) 个多项式 (0 sim m + 1) 处的点值。

    有点轻微卡常,需要将拉格朗日插值换成连续点值的 (mathcal{O}(m)) 插值。

    GO!
  • 相关阅读:
    day37 事务
    小组分享
    day36 pymysql 索引
    day 35 多表查询
    day 35 作业
    day 34 作业
    AST 节点类型对照表
    babel _shallowEqual.default
    js Proxy
    Symbol
  • 原文地址:https://www.cnblogs.com/Go7338395/p/15412937.html
Copyright © 2011-2022 走看看