题面:洛谷

题解:

  其实还可以用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. Session丢失——解决方案

    先抄下别人的作业(原帖:http://www.cnblogs.com/zhc088/archive/2011/07/24/2115497.html) Session丢失已经是一种习以为常的问题了,在自 ...

  2. https双向认证网站搭建

    新建网站 在搭建网站证书之前,我们先搭建好我们的网站 1.网站基本搭建 为我们的项目新建一个网站,按照如下的步骤来 1,打开IIS,右键单击网站弹出菜单,选择网站(如图1.1.1) 图1.1.1 2, ...

  3. 转载-找圆算法((HoughCircles)总结与优化-霍夫变换

    原文链接: http://www.opencv.org.cn/forum.php?mod=viewthread&tid=34096   找圆算法((HoughCircles)总结与优化 Ope ...

  4. Unity中StopCoroutine不起作用怎么办

    1,只有StartCoroutine使用一个字符串方法名时才能用StopCoroutine(string CoroutineName)停用. 2, public Coroutine coroutine ...

  5. Python数据结构 将列表作为栈和队列使用

    列表作为栈使用 Python列表方法使得列表作为堆栈非常容易,最后一个插入,最先取出(“后进先出”).要添加一个元素到堆栈的顶端,使用 append() .要从堆栈顶部取出一个元素,使用 pop()  ...

  6. flex布局与ellipsis冲突问题

    在flex布局里使用text-overflow: ellipsis;发现没有省略. 解决方案 .g-flex-c{ flex: 1; min-width: 0; }

  7. Wampserver 修改根目录

    wampserver 默认根目录在 www 文件夹下 修改根目录方法如下: 1. 在打算存放项目或代码的位置新建文件夹(我建在了C:/MyProject) 2. 打开 httpd.conf 文件(该文 ...

  8. 在Emacs 23里字体的调整(转自ChinaUnix.net)

    首先,在Emacs中,通过菜单Options --> Set Default Font,设置好你喜欢的字体. 然后,把光标放到你所在的字体上,用命令M-x describe-font来查看你当前 ...

  9. USACO 1.2.2 Transformations 方块转换

    Description 一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度 ...

  10. ZOJ 1842 Prime Distance(素数筛选法2次使用)

    Prime Distance Time Limit: 2 Seconds      Memory Limit: 65536 KB The branch of mathematics called nu ...