题面:洛谷

题解:

  其实还可以用AC自动机做,但是没调出来,,,不知道发生了什么。。。

  AC自动机做法如下:

    观察到如果我们对给定的每个串建AC自动机,那么直接拿大串在上面匹配,如果遇到了一个单词的终止节点,假设当前大串的位置是i,匹配到的节点是j,那么这个单词覆盖了

    [i - dep[j] + 1, i]这个区间(dep[j]即为单词长度)

    但是我们发现空间根本开不下。

    因为对每个串分别匹配不会影响结果,所以考虑每50个串我们重建一次AC自动机,然后匹配一次。

    匹配中的每次区间修改都用差分维护,那么最后对于每个权值大于等于1的位置都统计1 的贡献即为答案。

  后缀自动机做法如下:

    考虑统计对于每个位置而言,以i为结尾的最长被覆盖的长度

    我们对大串建立后缀自动机,然后对于每个小串都拿去自动机上匹配。假设我们最后匹配到的状态为x,既然这个状态已经被覆盖了,那么x在parent树上的子树也一定可以被覆盖。

    但是要对每个状态内的最长串长度MAXS取min,因为匹配到一个状态只能代表可以覆盖这个状态所代表的子串,且长度不能大于当前给定图案(小串)的长度。

    那么我们对每次匹配到的状态x打上标记,标记权值为当前小串的长度,如果有多个标记,取最大的那个。

    最后统计打完所有标记之后,对于每个节点都下传标记,下传的过程中依然对标记权值取max。

    最后即可得到对于每个位置而言,以i为结尾的最长被覆盖的长度。

    

    一个快速(好写)统计的方法:

      因为对于每个点下传标记就相当于对每个点接收来自它父亲的标记,那么我们只需要保证在接收点x的父亲的标记时,fa[x]已经接收过来自fa[fa[x]]的标记。

      因此我们按bfs序来更新标记就可以了,因为l[fa[x]](l[i]表示状态i的MAXS,即最长的保证right集合不变的长度)一定小于l[x],所以我们按照l[x]的大小来确定顺序即可。

  

 #include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 301000
#define ac 601000 int n, m, ans;
int b[AC], k[ac];
int d[AC], mark[ac];//差分数组
char s[AC]; inline void upmax(int &a, int b){
if(b > a) a = b;
} struct sam_atm{
int last, cnt;
int ch[ac][], fa[ac], l[ac], right[ac]; inline void add(int c, int i)
{
int p = last, np = ++ cnt;
last = np, l[np] = l[p] + , right[np] = i;
for( ; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
if(!p) fa[np] = ;
else
{
int q = ch[p][c];//获取第一个有c的节点的对应边所指向的节点
if(l[p] + == l[q]) fa[np] = q;//如果不会造成影响,那么就直接连fa
else
{
int nq = ++ cnt;//否则就再建新点
l[nq] = l[p] + ;
memcpy(ch[nq], ch[q], sizeof(ch[q]));//把q的信息赋值给nq,,,接下来nq相当于要取代q了
fa[nq] = fa[q], fa[q] = fa[np] = nq;
for( ; ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
}
}
} void find()
{
int len = strlen(s + ), now = ;
for(R i = ; i <= len; i ++)
{
if(!ch[now][s[i] - 'a']) return ;
now = ch[now][s[i] - 'a'];
}
upmax(mark[now], len);
} void work()
{
for(R i = ; i <= cnt; i ++) ++ b[l[i]];
for(R i = ; i <= n; i ++) b[i] += b[i - ];//这里只需要枚举到n,多枚举就re了
for(R i = ; i <= cnt; i ++) k[b[l[i]] --] = i;//为i赋b[l[i]]的排名
for(R i = ; i <= cnt; i ++) upmax(mark[k[i]], mark[fa[k[i]]]); for(R i = ; i <= cnt; i ++) //只能用有right的叶子节点更新
if(right[i]) ++ d[right[i] - mark[i] + ], -- d[right[i] + ];
for(R i = ; i <= n; i ++) d[i] += d[i - ];
for(R i = ; i <= n; i ++) ans += (d[i] > );
printf("%d\n", n - ans);
}
}T; void pre()
{
T.last = T.cnt = ;//这个又忘了。。。
scanf("%d%s", &n, s + );
for(R i = ; i <= n; i ++) T.add(s[i] - 'a', i);
scanf("%d", &m);
for(R i = ; i <= m; i ++) scanf("%s", s + ), T.find();
} int main()
{
// freopen("in.in", "r", stdin);
pre();
T.work();
// fclose(stdin);
return ;
}

[COCI2011-2012#5] POPLOCAVANJE 后缀自动机的更多相关文章

  1. luogu4595 [COCI2011-2012#5] POPLOCAVANJE 后缀自动机

    看着就像后缀自动机.... 然后搜了一下,网上一大把的\(AC\)自动机 嗯...... 不管了,打一个试试 然后就过了\(QAQ\) 我们考虑对于每个点\(i\)求出它往前最长能匹配的子串的长度 可 ...

  2. HDU 4436 str2int(后缀自动机)(2012 Asia Tianjin Regional Contest)

    Problem Description In this problem, you are given several strings that contain only digits from '0' ...

  3. hdu4436-str2int(后缀数组 or 后缀自动机)

    题意:给你一堆字符串,仅包含数字'0'到'9'. 例如 101 123 有一个字符串集合S包含输入的N个字符串,和他们的全部字串. 操作字符串很无聊,你决定把它们转化成数字. 你可以把一个字符串转换成 ...

  4. 后缀自动机(SAM)

    *在学习后缀自动机之前需要熟练掌握WA自动机.RE自动机与TLE自动机* 什么是后缀自动机 后缀自动机 Suffix Automaton (SAM) 是一个用 O(n) 的复杂度构造,能够接受一个字符 ...

  5. 字符串(多串后缀自动机):HDU 4436 str2int

    str2int Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total S ...

  6. 后缀自动机/回文自动机/AC自动机/序列自动机----各种自动机(自冻鸡) 题目泛做

    题目1 BZOJ 3676 APIO2014 回文串 算法讨论: cnt表示回文自动机上每个结点回文串出现的次数.这是回文自动机的定义考查题. #include <cstdlib> #in ...

  7. 回文树&后缀自动机&后缀数组

    KMP,扩展KMP和Manacher就不写了,感觉没多大意思.   之前感觉后缀自动机简直可以解决一切,所以不怎么写后缀数组.   马拉车主要是通过对称中心解决问题,有的时候要通过回文串的边界解决问题 ...

  8. HDU 1403 Longest Common Substring(后缀自动机——附讲解 or 后缀数组)

    Description Given two strings, you have to tell the length of the Longest Common Substring of them. ...

  9. HDU 4436 (后缀自动机)

    HDU 4436 str2int Problem : 给若干个数字串,询问这些串的所有本质不同的子串转换成数字之后的和. Solution : 首先将所有串丢进一个后缀自动机.由于这道题询问的是不同的 ...

随机推荐

  1. sqlserver 导出数据到Excel

    1.导出非正式Excel EXEC master..xp_cmdshell 'bcp t.dbo.tcad out D:\MySelf\output\Temp.xls -c -q -S".& ...

  2. 【MySQL函数】replace()函数

    1.replace()函数 语法:replace(a,b,c) a的b部分被c替换 案例:select replace(abcde,bcd,123)-- 结果a123e

  3. Linux学习(一)------CentOs安装mysql5.5 数据库

    具体方法和步骤如下所示: 1.第一步就是看linu是否安装了mysql,经过rpm -qa|grep mysql查看到centos下安装了mysql5.1,那就开始卸载咯 2.接下来就是卸载mysql ...

  4. Maven学习(十七)-----Maven外部依赖

    Maven外部依赖 正如大家所了解的那样,Maven确实使用 Maven 库的概念作依赖管理.但是,如果依赖是在远程存储库和中央存储库不提供那会怎么样? Maven 提供为使用外部依赖的概念,就是应用 ...

  5. java计算工龄

    计算工龄原则:若是2000-10-12作为开始工作时间,则到下一年的2001-10-13算为一年.有个bug,不满一年的工龄是错误的. import java.util.Date;import jav ...

  6. Halcon学习网

    重码网是一个在线机器视觉学习网站,推出了Halcon,Visionpro机器视觉学习视频教程,视频内容通俗易懂,没有编程基础的同学,照着视频练习,也同样可以学会. 学机器视觉,拿高薪,成就技术大拿.重 ...

  7. 2018-2019-20172329 《Java软件结构与数据结构》第四周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第四周学习总结 经过这样一个国庆节的假期,心中只有一个想法,这个国庆假期放的,不如不放呢!! 教材学习内容总结 < ...

  8. Ubuntu16.04下 protobuf3.4.0 的安装与卸载

    感谢原文作者:https://blog.csdn.net/xiexievv/article/details/47396725 一. 安装 下载protobuf protobuf下载地址:https:/ ...

  9. Spring 依赖的Jar包简介

    Spring 依赖的Jar包简介 Spring的依赖关系 依赖关系分组 JAR文件 说 明 ant ant.jar, ant-junit.jar, ant-launcher.jar Spring采用A ...

  10. .NET中的堆(Heap)和栈(Stack)的本质

    计算机的内存可以分为代码块内存,Stack内存和Heap内存.代码块内存是在加载程序时存放程序机器代码的地方. 栈(Stack)一般存放函数内的局部变量. 堆(Heap)一般存放全局变量和类对象实例等 ...