• Atcoder ARC-060


    ARC060(2020.7.8)

    A

    背包板子

    B

    首先感觉这个东西应该不能直接 (O(1)) 算出来,那么复杂度应该就是 (O(log n), O(sqrt{n}), O(sqrt{n} log n)) 之类的,看数据范围可以猜到应该不是 (O(log n)) 的(其实是不知道怎么做)。于是按照套路我们考虑根号分治,可以考虑枚举这个 (b),那么对于 (b le sqrt{n}) 的部分,直接枚举即可,再 (O(log n)) 判断。然后我们可以发现对于 (b > sqrt{n}) 的部分,因为 (b ^ 2 > n) 那么 (n)(b) 进制下最多只有两位,那么不妨设 (pb + q = n)(p + q = s) 两式相减可得,(p(b - 1) = n - s),则 (b - 1 mid n - s) 于是可以考虑枚举 (n - s) 小于 (sqrt{n - s}) 的约数 (d) 那么 (b - 1 = frac{n - s}{d}) 这一部分的复杂度同样是 (O(sqrt{n} log n)) 的,因此总复杂度 (O(sqrt{n} log n)).

    C

    可以发现我们可以预处理出每个点再一天内往后最远能到达的点,于是问题就变成问从一个点最少往后跳几次能跳过另一个点,那么我们可以直接分块处理,预处理出一个点走出块内第一个点需要的最短跳跃次数,于是查询只需要跳块即可。那么复杂度就可以做到 (O(n sqrt{n})) 了,那么还有没有更优秀的做法呢?实际上是有的,可以考虑倍增,那么类似于求 ( m LCA) 的倍增方式跳到下标小于另一个点的第一个点,次数 (+1) 即是答案。

    D

    首先有一些特殊情况,首先如果原串是不循环的,那么答案就是 (1, 1),其次如果原串中的每个元素都相同,那么答案就是 (n, 1),对于剩下的情况,我认为将原循环串去掉最后一位剩下的串不可能是一个循环串,于是我大胆地猜测第一问的答案是 (2)结果还猜对了。下面是一个关于字符串循环节很关键的一个性质:

    给定两个正整数 (p, q) 如果一个长度不小于 (p + q - gcd(p, q)) 的串 (S) 中存在长度为 (p, q) 的循环节,那么 (gcd(p, q)) 也是 (S) 的循环节。

    考虑将循环的意义用数学语言表达下来,不难发现对于 (forall i in [1, n])(S_i = S_{i + p} = S_{i + q} = S_{i + px + qy}),根据裴蜀定理考虑到 (px + qy = gcd(p, q)) 是一定有解的,那么就会有 (S_i = S_{i + gcd(p, q)}) 也就意味着 (gcd(p, q)) 也是一个循环节。

    那么我们将原串去掉最后一位之后假设剩下的串最小循环节长度为 (x),原串最小循环节长度为 (y),因为 (gcd(n - 1, n) = 1) 因此 (n - 1, n) 不会包含相同约数,因此 (gcd(x, y) = 1),那么根据上面的性质,将原串继续按照循环节延长,那么 (1 sim x imes y) 这一段子串就一定会含有 (x, y) 两种循环节,那么 (gcd(x, y) = 1) 也会是一种循环节,因此原串中每一个字符都将相等与条件矛盾。

    那么下面我们就只需要枚举中间的断点,判断左右是否都是不循环的即可。接下来又是一个非常重要的结论,一个字符串存在循环节的充要条件是 (exist x mid n, S_{1, n - x} = S_{x + 1, n})

    首先假设 (S_{1, x}) 是上图中的绿色部分,其他颜色分别是长度为 (x) 的块,因为 (S_{1, n - x} = S_{x + 1, n}) 那么相同颜色块应该相同,又根据在原串中的位置可以得到绿色块和黄色块相同,同理又可以得到黄色块和红色块相同,以此类推可以得到原串是个循环串。

    得到循环串的判定条件后我们发现需要枚举这个长度 (x),又因为 (x mid n) 那么我们可以枚举 (n) 的约数,事实上因为我们需要知道的是前缀是否是循环的,那么第一个循环节都会是从 (1) 开始的,那么我们枚举第一个循环节的长度,那么能以该长度作为循环节的只有其倍数,那么我们再枚举一下其倍数 ( m Hash) 一下就可以 (O(1)) 判断了,后缀也是类似的。那么最终统计答案就非常简单了。

    可以发现上面那个做法的复杂度是 (O(n ln n)) 的,那么能不能做到 (O(n)) 呢?事实上是可以的,需要使用到 (kmp) 的性质。

    首先我们可以将判断是否循环的条件改成 (n - nxt_{n} mid n)。首先我们可以知道如果 (n - nxt_{n} mid n) 那么是一定有循环节的,类似上面的证明。下面来证明对于 (n - nxt_{n} mid n) 的情况不存在循环节。

    首先考虑 (nxt) 数组的定义,不难发现有 (S_{1, nxt_n} = S_{n - nxt_n + 1, n}),那么类似于第一种做法循环节的证明方法,可以发现 (S_{1, n - nxt_n}) 也可以在原串中循环只是不能刚好循环完毕,即最后一次循环只能出现部分。我们称这种循环节为伪循环节。

    首先令 (x = n - nxt_n),假设存在一个长度为 (len) 的循环节,显然 (len e x)。首先如果 (len < x),那么显然 (nxt_n) 可以变大,矛盾。如果 (x mid len) 既然 (len) 都能循环那么 (x) 一样能循环,矛盾。对于 (x mid len) 的情况,因为 (x mid len) 那么一定存在一个伪循环节会跨过第一个循环节和第二个循环节,假设这个伪循环节是第 (k) 个,那么 (S_{len + 1, len + x} = S_{1, x} = S_{k imes x + 1, (k + 1) imes x}) 可以发现 (S_{len + 1, len + x}, S_{k imes x + 1, (k + 1) imes x}) 重叠了一段区间且长度相同,那么 (S_{len + 1, k imes x}) 就可以作为一段新的伪循环节,且长度小于 (x),那么 (nxt_n) 一样可以变大,矛盾。

    那么我们 (kmp) 可以求出每个位置的 (nxt) 值,前缀后缀判断是可以 (O(1)) 做到的,因此总复杂度 (O(n)).

    实际上循环节还有一个很奇妙的性质,即所有循环节长度都是最小循环节长度的倍数。假设存在两个个长度为 (p, q(gcd(p, q) e p)) 的循环节,(p) 为长度最小的循环节。那么显然有 (gcd(p, q) < p),根据最开始的那条性质,(gcd(p, q)) 也是一个循环节,那么最小循环节的长度就会是 (gcd(p, q)) 而不是 (p),矛盾。

    GO!
  • 相关阅读:
    SCSI contrller的几种类型的区别
    ScaleIO与XtremSW Cache如何集成呢?
    如何强制使用某一大小的包去ping某个IP地址?
    如何查看ETW Trace?
    图像卷积与滤波的一些知识点(转)
    tensorflow serving 编写配置文件platform_config_file的方法
    python在linux的报错集锦
    某些数组和字符串类型转换(转)
    系统安装-007 CentOS7yum源添加、删除及其yum优化(转)
    Error:Failed to resolve: android.arch.core:common:1.1.0
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13675905.html
Copyright © 2020-2023  润新知