zoukankan      html  css  js  c++  java
  • 洛谷P5576 [CmdOI2019]口头禅(字符串)

    洛谷P5576 [CmdOI2019]口头禅(字符串)

    题目描述

    蒟蒻出题人收集了某位大佬的(n)条语录,并按照时间排序,编号为(1...n)

    他发现这位大佬的口头禅是随着时间而变化的,而且里面有些看不懂的内容。

    在请教了群DS带师之后,他得到了某种hash方法,把这些语录都变成了01串,这样好懂一些。

    为了研究水群的奥秘,他进行了多次询问:([l,r])之间的所有语录,最长公共子串的长度是多少?

    数据范围

    subtask编号 n m 语录总长 分值
    1 50 50 500 10
    2 50 50 80000 15
    3 2000 10000 160000 15
    4 20000 (10^5) 400000 15
    5 20000 (10^5) 400000 45

    对于subtask4 : 语录生成后,之间的顺序经过随机打乱。

    对于subtask5 : 空间限制为50Mb,其他的数据为500Mb

    解题思路

    后缀自动机

    首先先膜出题人 @command_block

    很神奇的思路

    首先要会用后缀自动机来求多串的最长公共字串

    两个做法,一个是对一个字符串建后缀自动机,然后将其他串在上面打标记,记录匹配到节点 x 的最长长度是多少,另一个方法是选一个字符串 S,剩下的分别建后缀自动机,然后这个字符串分别在其他串上跑,记录 (f[x]) 表示 S[1...x] 能够匹配的最长后缀是多少。本题两种方法均可。

    那么神仙的分治就来了

    倍增分治

    对于一个区间,将长度小于等于 (2^x) 的串提出来进行分治,直到子区间没有这样的串为止,这时候我们 ++x 继续此过程

    显然我们有一个 x 最大深度是 (log N) 的,又一共有 (log N) 个 x,总分治深度是 (log^2 N),但实际上并跑不满

    为什么要这么分治,显然我们使用后缀自动机时选出的字符串大小越小越好,这样我们才能方便的记录前缀信息和后缀信息,否则空间都开不下

    询问答案

    考虑跨过区间 mid 的答案,记录从 mid 开始的前缀 f 和后缀 f,查询时合并答案即可

    时间复杂度证明

    考虑区间字符串长度总和为 len,区间长度为 k,最小的串长度则不超过 (frac {len}k)

    扫一遍此区间的复杂度为 (Theta(k * frac {len}k) = Theta(len)),所以分治扫所有的区间记录前缀后缀时间复杂度是 (Theta(lenlog^2N))

    如果串长小于 (frac {len}{sqrt m}),有复杂度 (Theta(lensqrt m))

    如果串长大于 (frac {len}{sqrt m}) 则无法保证复杂度,但很好的发现 k 小于 (sqrt m),想一想,为什么,也就是本质不同区间有 (k^2) 个,记忆化一下可以得到 (Theta(mlog m+k^2*frac {len}{k}) = Theta(mlog m+len*k))

    代码就先不放了

    另一种思路-SA做法

    这题 SA 被卡空间了,所以我懒了还没有写,但不妨作为一种启发,如果有 dalao 发现了什么问题欢迎来踩和讨论,毕竟我只是口胡

    感谢 @z7z_eta 的帮助

    SA求多串最长公共子串

    看到这题你应该有些基础,我就稍微简略些吧

    将所有串首尾相连拼起来求 SA 数组,将 height 数组看成隔板,从大到小拆,直到所有串的后缀均在某一个区间内出现,这个 height 就是答案

    如何看所有串均出现在某一个区间呢

    set 启发式合并

    每个位置开个 set,维护当前联通块的 “颜色” (每个原串是一种颜色)集合,当然我们维护区间会好一些,比如 2,3,4,5 颜色可以直接压成 [2,5],在用上启发式合并就可以 (Theta(Nlog^2N)) 的维护了,注意启发式合并时不要看 set 的 size 而是颜色的个数

    在本题中可以发现如果颜色区间 [l, r] 被某一次包含就是答案了,问题又来了,如何看 [l, r] 最早什么时候被包含呢

    扫描线

    不妨将区间看成二维平面上的点 (L, R),那么在 set 中合并时比如有 ([1, 3], [5,6]),这时新插入一个区间 ([4,4]),会使 set 中的区间融合 ([1,6]),那么新的大区间所包含的所有小区间答案和当前的答案取 max 就行了,那么 ([1, 6]) 可以看成二维平面上的一个矩形 ([1,6],[1,6]),对里面的点取 max 即可,发现所有的点都在 (y = x) 的上方,矩形可以换成 ([1,+infty],[-infty,6]),这样扫描线加树状数组即可维护,单独是 (Theta(nlog n)) 的,但事实上启发式合并会产生 (Theta(nlog n)) 个矩形,所以总复杂度 (Theta(n log^2n))

    时间复杂度 (Theta(lenlog len+lenlog^2 n+n log^2 n)),空间复杂度 (Theta(n log n))

    这个做法比较好想,但应该没有 sam 快,但那个太难想了啊

  • 相关阅读:
    poj2387Til the Cows Come Home(dijkstra)
    poj2349Arctic Network
    poj1789Truck History
    zoj1586QS Network
    poj2421Constructing Roads
    poj2301Building a Space Station(最小生成树)
    poj1287Networking(最小生成树)
    myeclipse配置svn亲测
    MyEclipse8.6安装svn(非link方式)
    myeclipse一些技巧
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13121957.html
Copyright © 2011-2022 走看看