博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj2780】[Spoj]8093 Sevenk Love Oimaster 广义后缀自动机
阅读量:4361 次
发布时间:2019-06-07

本文共 2364 字,大约阅读时间需要 7 分钟。

题目描述

Oimaster and sevenk love each other.

But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman's nature, sevenk felt angry and began to check oimaster's online talk with ChuYuXun.    Oimaster talked with ChuYuXun n times, and each online talk actually is a string.Sevenk asks q questions like this,    "how many strings in oimaster's online talk contain this string as their substrings?"

输入

There are two integers in the first line, 
the number of strings n and the number of questions q.
And n lines follow, each of them is a string describing oimaster's online talk. 
And q lines follow, each of them is a question.
n<=10000, q<=60000 
the total length of n strings<=100000, 
the total length of q question strings<=360000

输出

For each question, output the answer in one line.

样例输入

3 3

abcabcabc
aaa
aafe
abc
a
ca

样例输出

1

3
1


题目大意

给出n个字符串和q个询问,每次询问给定的字符串在多少个字符串中出现过(为多少个字符串的子串)。

题解

这种单字符串为多字符串的子串的问题,当然要用广义后缀自动机

对于后缀自动机上的每个节点,我们再开两个数组vis和si,记录一下它最后一个属于的字符串是什么,以及它属于多少个字符串。

那么当插入一个字符之后,应该更新它的vis和si信息,如果vis不等于当前字符串,则将vis更新,并将si++。由于它的parent树上的祖先节点与它有着相同信息,应该一起更新,即不断向上寻找fa,直到不存在fa或已经被更新过为止。

同时,当插入过程中新建节点nq时,由于它是用来代替q的,所以应该把q的vis、si赋给nq。

大量实践证明,这样做的时间复杂度是$O(n)$的(其实我也不太会证)

最后对于每个询问串,在后缀自动机中沿next不断查找,最后节点的si即为答案。

#include 
#include
#include
#define N 400010using namespace std;int next[N][26] , fa[N] , dis[N] , vis[N] , si[N] , last , tot = 1;char str[N];void insert(int c , int t){ int p = last , np = last = ++tot; dis[np] = dis[p] + 1; while(p && !next[p][c]) next[p][c] = np , p = fa[p]; if(!p) fa[np] = 1; else { int q = next[p][c]; if(dis[q] == dis[p] + 1) fa[np] = q; else { int nq = ++tot; memcpy(next[nq] , next[q] , sizeof(next[q])) , si[nq] = si[q] , vis[nq] = vis[q] , dis[nq] = dis[p] + 1 , fa[nq] = fa[q] , fa[np] = fa[q] = nq; while(p && next[p][c] == q) next[p][c] = nq , p = fa[p]; } } for(p = np ; p && vis[p] != t ; p = fa[p]) vis[p] = t , si[p] ++ ;}int main(){ int n , m , i , j , l; scanf("%d%d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) { scanf("%s" , str) , l = strlen(str); for(j = 0 , last = 1 ; j < l ; j ++ ) insert(str[j] - 'a' , i); } while(m -- ) { scanf("%s" , str) , l = strlen(str); for(i = 0 , j = 1 ; i < l ; i ++ ) j = next[j][str[i] - 'a']; printf("%d\n" , si[j]); } return 0;}

 

 

转载于:https://www.cnblogs.com/GXZlegend/p/7114767.html

你可能感兴趣的文章
Ubuntu下安装mysql与mysql workbench
查看>>
HDOJ1251解题报告【字典树】
查看>>
java 字符串zlib压缩/解压
查看>>
httpclient新旧版本分割点4.3
查看>>
实现小数据量和海量数据的通用分页显示存储过程
查看>>
JPEG文件结构
查看>>
jquery api 笔记(2) 事件 事件对象
查看>>
10.17NOIP模拟赛
查看>>
Opus 和 AAC 声音编码格式
查看>>
探索Split函数第三位参数的用法
查看>>
应用程序无法启动,因为应用程序的并行配置不正确
查看>>
Python单元测试——unittest
查看>>
The document cannot be opened. It has been renamed, deleted or moved.
查看>>
ios中@class和 #import,两种方式的讨论
查看>>
OpenStack,ceph
查看>>
Odoo 8.0 new API 之Environment
查看>>
页面传值中get和post区别
查看>>
PHP-CGI漏洞成因原理剖析和利用
查看>>
20145212 罗天晨 《网络对抗》Exp3 Advanced 恶意代码伪装技术实践
查看>>
访问快科技(驱动之家)某个新闻会自动跳转到web.techtoutiao.win
查看>>