• [NOI2018]你的名字


    题目描述

    (A) 被选为了 (ION2018) 的出题人,他精心准备了一道质量十分高的题目,且已经把除了题目命名以外的工作都做好了。

    由于 (ION) 已经举办了很多届,所以在题目命名上也是有规定的,(ION) 命题手册规定:每年由命题委员会规定一个小写字母字符串,我们称之为那一年的命名串,要求每道
    题的名字必须是那一年的命名串的一个非空连续子串,且不能和前一年的任何一道题目的名字相同。

    由于一些特殊的原因,小 (A) 不知道 (ION2017) 每道题的名字,但是他通过一些特殊手段得到了 (ION2017) 的命名串,现在小 (A)

    (Q) 次询问:每次给定 (ION2017) 的命名串和 (ION2018) 的命名串,求有几种题目的命名,使得这个名字一定满足命题委员会的规定,即是 (ION2018) 的命名串的一个非
    空连续子串且一定不会和 (ION2017) 的任何一道题目的名字相同。

    由于一些特殊原因,所有询问给出的 (ION2017) 的命名串都是某个串的连续子串,详细可见输入格式。

    先考虑 (l=1,r=|S|) 的情况 ((68pts))

    我们可以对 (S) 建出 (SAM),把 (T) 扔到上面跑匹配得到数组 (L)

    如果不考虑本质不同这一限制,那么答案就是 (sumlimits_{i=1}^{|T|}i-L[i])

    然后考虑怎么去重,我们同时对 (T) 建出 (SAM),同时对每个点处理出 (pos[i]),即该状态第一次出现位置

    那么每个点对答案的贡献就是 (sumlimits_{i=1}^{tot}len[i]-max(len[f[i]],L[pos[i]]))

    然后考虑任意区间的情况 ((100pts))

    发现我们需要快速得到一个区间的 (SAM),然而并没有什么好的方法

    再仔细想想,我们真的一定要得到这段区间的 (SAM) 吗?

    其实我们只需要借助 (SAM) 求出 (L) 数组

    而观察 (l=1,r=|S|) 的情况,对于 ([l,r]) 我们需要以下几种操作

    • 1.查询点 (x) 在 [l,r] 内是否有 (c) 这个转移

    • 2.跳 (parent)

    • 3.得到一个节点的 (len)

    发现其实在 ([1,|S|])(SAM) 上也可以实现这些操作,主要问题在于怎么查询点 (x) 在 [l,r] 内是否有 (c) 这个转移

    发现这本质上是求点 (ch[x][c])(endpos) 集合中是否有 ([l+length,r]) 之间的点

    处理一下 (endpos) 集合就可以查询了

    还有就是我们跳 (parent) 前应该先减小 (length) 查询是否匹配

    总复杂度 (O(|S|log|S|+sumlimits_{i=1}^Q |T_i|log|T_i|))

  • 相关阅读:
    CloudAlibaba
    搭建一个Vue项目
    命令合集
    luoguP3224 [HNOI2012]永无乡【线段树,并查集】
    luoguP3521 [POI2011]ROTTree Rotations【线段树】
    luoguP4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (线段树权值动态开点,树链剖分)
    字符串类模板及总结(随缘更新)
    codeforces600E Lomsat gelral【线段树合并/DSU】
    codeforces963D. Frequency of String【哈希】
    "蔚来杯"2022牛客暑期多校训练营9 G Magic Spells【马拉车+哈希】
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/12100104.html
Copyright © 2020-2023  润新知