题面:洛谷

题解:

  其实还可以用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. 属性文件操作之Properties与ResourceBundle

    1.Properties与ResourceBundle 两个类都可以读取属性文件中以key/value形式存储的键值对,ResourceBundle读取属性文件时操作相对简单. 2.Propertie ...

  2. javaweb(三十四)——使用JDBC处理MySQL大数据

    一.基本概念 大数据也称之为LOB(Large Objects),LOB又分为:clob和blob,clob用于存储大文本,blob用于存储二进制数据,例如图像.声音.二进制文等. 在实际开发中,有时 ...

  3. VS2008 "无法找到资源编译器dll 请确保路径正确"

    系统环境:windows 8.1 企业版 x64 (装有 .NET 2.0 / 3.5 / 4.0 /  4.5) 安装前确认系统已安装 .NET 2.0 / 3.5 .在安装时,最好是默认安装,并且 ...

  4. Windows下使用Python的Curses库时 No module named _curses问题

    这个问题产生的 根本原因 是 curses 库不支持 windows.所以我们在下载完成python后(python 是自带 curses 库的),虽然在  python目录\Lib  中可以看到 c ...

  5. JUC——线程同步锁(锁处理机制简介)

    锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...

  6. 经典教程|10 分钟速成 Python3

    Python 是由吉多·范罗苏姆(Guido Van Rossum)在 90 年代早期设计. 它是如今最常用的编程语言之一.它的语法简洁且优美,几乎就是可执行的伪代码. 注意:这篇教程是基于 Pyth ...

  7. Java跨平台的实现原理

    不同操作系统支持的指令集有所差异,只要在不同操作系统上安装对应的jvm,jvm负责把Java字节码翻译成对应机器的二进制码,从而实现java语言的跨平台.

  8. Python常用模块之hashlib

    Python里面的hashlib模块提供了很多加密的算法,这里介绍一下hashlib的简单使用事例,用hashlib的md5算法加密数据 import hashlib hash = hashlib.m ...

  9. 20181009-3 Scrum立会报告+燃尽图02

    此作业要求:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2190] 一.小组介绍 组长:王一可 组员:范靖旋,王硕,赵佳璐,范洪达,祁 ...

  10. c# apache服务器请求得到数据(初级)

    1.代码: string data = new WebClient().DownloadString("http://localhost:81/123.txt");