zoukankan      html  css  js  c++  java
  • AC自动机

    例题(从易到难):
    模板
    poi 病毒

    模板题,没什么营养价值
    建立Trie图后tarjan判环即可。

    CF710F

    模板题,没什么营养价值
    二进制分组+AC自动机即可。

    lg3121

    以前在jzoj上做过单串版本。
    用AC自动机+栈,每次插入一个字符,维护在AC自动机上的匹配点。
    栈中维护从栈底匹配到栈的某个点在AC自动机上的节点。
    当栈顶能够被匹配,则弹出匹配的字符串。

    [JSOI2007]文本生成器

    简单题。
    用容斥,转化成不可读的单词的个数。
    显然用dp,设(f_{i,j})表示长度为(i),走到第(j)个节点。
    把可读单词标记成不能访问,(j)不能访问标记点。

    [BJOI2017]魔法咒语

    把禁止串在AC自动机上标记,不能访问。
    (f_{i,j})表示第(i)个节点,转移到(j)的方案。
    转移显然。
    后面基本词汇最多为(2)的情况只会转移到(f_{i+2,k}),用矩阵乘法拆点维护(f_{i},f_{i+1})即可转移。

    [HNOI2006]最短母串问题

    字典序最小很难做。
    发现一个字符串上一个字符如果没被任何合法串覆盖,则删除更优。
    (f_{i,j})表示状态为(i),最后一个字符串为(j)的最小长度。
    枚举(i,j)串能够拼接起来的长度转移。
    在比较字典序时用string即可。

    lg3311
    CF585F
    CF163E

    简单题
    考虑把原串拿到AC自动机上去匹配,在匹配的过程中计算答案。
    当匹配到(i)时,(i)结尾的方案数就是fail树上它到根节点的被激活节点数
    用dfs序+bit维护即可。
    CF1437G

    做法0:考虑LCT/树剖,显然一个字符串匹配到第(i)个位置,答案就是fail树上到根的权值最大值。
    用树剖/LCT维护
    做法1:考虑线段树,根据前面的分析,我们要支持修改和查询一个点到根的最大值。
    考虑离线求。
    dfs整个fail树,维护以时间为下标的线段树。
    把所有修改操作挂在fail树上,然后在dfs到某个点时,运行其对应修改操作。
    把所有在这个节点的修改操作按照时间排序,如果某个操作的生效时间为([l,r]),则把线段树上([l,r])对修改值取最大值。
    查询时直接查询当前操作时间对应结果即可。
    用可回退化线段树(用栈记录操作),时间复杂度$O(nlog_2n)

    阿狸的打字机
    jzoj4348

    把询问串在AC自动机上匹配,我们需要知道fail树到根节点上和(s,t)路径匹配的节点数量。
    树链剖分后把链按照dfs序重标号,则事实上拆成了连续的(log_2n)条链。
    知道fail树上到根的连续标号节点的值可以可持久化线段树。

    CF1400F

    CF547E

    先差分,变成询问(s_k)(s_{1...x})中出现多少次。
    考虑按照(x)扫描线
    从小到大插入(s_i),考虑它对某个字符串的贡献。
    它事实上是(s_i)每个前缀的节点所代表的字符串到根路径的节点值+1,用dfs序+bit维护。
    查询也可以dfs序+bit,查询对应节点子树节点个数即可。
    cf590E
    lg5840

    套路题
    发现(T)改变,考虑对(s_i)建立AC自动机。
    每插入一个字符串时,把这个字符串在AC自动机上匹配。
    在匹配时,所有匹配节点到根节点的链上的所有点都要+1。
    事实上这是经典的问题。
    可以按照dfs序排序,相邻两个点的lca处权值-1,每个点的权值+1,则一个点末尾的字符串个数就是它到根的权值和。
    用dfs序+bit维护。

    回忆树

    考虑树分治,每次在当前路径(x->y)包含重心时计算答案。
    设当前重心为(c)
    考虑(c->x),(c->y)对答案的影响,可以把这条路径的字母在AC自动机上匹配,用bit把访问过的节点打上标记。
    在dfs出当前节点后撤回。
    然后查询(s)子树上是否有标记点。
    然而事实上我们发现(s)跨过重心的没有求。
    这部分可以暴力(kmp),这是因为跨过重心的对答案有影响的串长度只有(O(|2S|))

    CF587F
    bzoj3768
    CF1110H
    lg7582

    做法1:分块
    sub2可以ac自动机套线段树。
    全部数据可以ac自动机套分块。
    每个块维护add,fz标记,表示当前块先被赋值成fz,然后加上add。
    在区间赋值时add=0,fz=值
    在区间加法是add+=val
    给每个节点额外维护一个val,表示val+fz+add是原值。
    在区间加法/赋值时散块节点可以先查询原值,然后就能知道新值。
    在查询时,非整块用AC自动机+dfs序。
    这需要快速知道一个节点的值,用val+fz+add即可。
    整块用AC自动机,把当前串在AC自动机上匹配。
    这事实上需要知道一个点到根节点的路径值。
    先求出每个节点只有val的答案,用dfs序+bit。
    这样子散块赋值就只需要更新(sqrt{n})个bit了。
    然后由于整个块的val,fz都是一样的,只需要知道当前节点fail树到根的节点个数即可。

    [xr4]文本编辑器

    loj6681

    CF917E

    [GDOI2019]小说

    先考虑60分做法。

    [GDOI2019]小说 加强版

    由于要求精确解,不能分数规划了。

  • 相关阅读:
    JVM -- Full GC触发条件总结以及解决策略
    java实现-图的相关操作
    Integer的intValue()方法
    Java transient关键字
    Redis 单线程模型介绍
    String类的intern()方法 -- 重用String对象,节省内存消耗
    数据库阿里连接池 druid配置详解
    redis 实现发布/订阅模式
    Redis实现队列
    redis 实现分布式锁
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/13743421.html
Copyright © 2011-2022 走看看