题面:洛谷

题解:

  其实还可以用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. IBM X3650M4简单排错方法

    如果出问题了,首先看开机的那个地方的灯是否显示正常,有黄色的灯亮一般都不正常: 这种服务器带有一个错误指示板,只需要在电源开关那,如上图,把那个蓝色的按钮往里面按,就能把里面的一个板子抽出来,可以看到 ...

  2. unity游戏在ios11上不显示泰语解决办法

    最近在开发中遇到unity游戏在ios11上不显示泰语的问题,全部显示为方框内一个问号. 通过搜索发现这是Unity的一个bug,在2017.3中修复了 但升级unity风险很大,所以我采用了该文中提 ...

  3. selenium自动化之稳定版本环境介绍

    大家都知道,目前selenium版本已经升级到3.0了,selenium3只是在selenium2的基础上做了一些调整,最明显的区别就是 selenium2对Firefox的支持最高只支持46及以下版 ...

  4. Python接口测试实战4(下) - 框架完善:用例基类,用例标签,重新运行上次失败用例

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  5. Python 3 利用 Dlib 实现摄像头人脸检测特征点标定

    0. 引言 利用 Python 开发,借助 Dlib 库捕获摄像头中的人脸,进行实时人脸 68 个特征点标定: 支持多张人脸: 有截图功能: 图 1 工程效果示例( gif ) 图 2 工程效果示例( ...

  6. Elasticsearch 统计代码例子

    aggs avg 平均数 最近15分钟的平均访问时间,upstream_time_ms是每次访问时间,单位毫秒 { "query": { "filtered": ...

  7. [T-ARA][HUE]

    歌词来源:http://music.163.com/#/song?id=22704406 wa du seu mo geum to yo do ga tae 어딜가도 스페셜한게 없어 [eo-dil ...

  8. Qt应用程序重启

    重启应用程序是一种常见的操作,在Qt中实现非常简单,需要用到QProcess类一个静态方法: // program, 要启动的程序名称 // arguments, 启动参数 bool startDet ...

  9. android开发问题 Failed to pull selection 菜鸟记录

    在eclipse中开发创建了一个sqlite数据库文件,为了查看数据库文件的内容,决定复制到PC上一看究竟,位置在data……里 当我点击ddms文件浏览里的pull a file from the ...

  10. ES6的新特性(15)——Promise 对象

    Promise 对象 Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了 ...