spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)
spoj 1812 LCS2 - Longest Common Substring II
题意:
给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串。
限制:
1 <= n <= 10
|A[i]| <= 1e5
思路:
和spoj 1811 LCS几乎相同的做法
把当中一个A建后缀自己主动机
考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1], Max(s))就能够更新答案。
注意:
我们求的是对于随意一个Right集合中的r。最大的匹配长度。那么对于一个状态s。它的结果自然也能够作为它Parent的结果,我们能够从底到上更新一遍。
这个能够通过一次拓扑排序搞定。
/*spoj 1812 LCS2 - Longest Common Substring II
题意:
给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串。 限制:
1 <= n <= 10
|A[i]| <= 1e5
思路:
和spoj 1811 LCS几乎相同的做法 把当中一个A建后缀自己主动机
考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1], Max(s))就能够更新答案。 注意:
我们求的是对于随意一个Right集合中的r,最大的匹配长度。那么对于一个状态s,它的结果自然也能够作为它Parent的结果。我们能够从底到上更新一遍。
这个能够通过一次拓扑排序搞定。 */
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1e5 + 5;
char str[15][N]; int maxx[2 * N], minn[2 * N]; struct SAM {
struct Node {
int fa, ch[27];
int val;
void init() {
fa = val = 0;
memset(ch, 0, sizeof(ch));
}
} node[2 * N]; int tot;
int new_node() {
node[++tot].init();
return tot;
} int root, last;
void init() {
root = last = tot = 1;
node[0].init();
node[1].init();
} void add(int x) {
int p = last;
int np = new_node(); node[np].val = node[p].val + 1;
while(p && node[p].ch[x] == 0) {
node[p].ch[x] = np;
p = node[p].fa;
}
if(p == 0)
node[np].fa = root;
else {
int q = node[p].ch[x];
if(node[p].val + 1 == node[q].val)
node[np].fa = q;
else {
int nq = new_node(); node[nq].val = node[p].val + 1;
memcpy(node[nq].ch, node[q].ch, sizeof(node[q].ch));
node[nq].fa = node[q].fa;
node[q].fa = node[np].fa = nq;
while(p && node[p].ch[x] == q) {
node[p].ch[x] = nq;
p = node[p].fa;
}
}
}
last = np;
}
void debug() {
for(int i = 1; i <= tot; ++i) {
printf("id=%d, fa=%d, step=%d, ch=[ ", i, node[i].fa, node[i].val);
for(int j = 0; j < 26; ++j) {
if(node[i].ch[j])
printf("%c,%d ", j+'a', node[i].ch[j]);
}
puts("]");
}
} void gao(int);
} sam; int du[2 * N];
int que[2 * N], fr, ta;
int b[2 * N], b_tot; void SAM::gao(int n) {
init();
int len1 = strlen(str[0]);
for(int i = 0; i < len1; ++i)
add(str[0][i] - 'a'); //debug(); b_tot = fr = ta = 0;
for(int i = 1; i <= tot; ++i)
++du[node[i].fa];
for(int i = 1; i <= tot; ++i)
if(du[i] == 0) que[ta++] = i, b[b_tot++] = i;
while(fr != ta) {
int u = que[fr++];
int v = node[u].fa;
--du[v];
if(du[v] == 0) que[ta++] = v, b[b_tot++] = v;
} for(int i = 1; i <= tot; ++i)
minn[i] = node[i].val;
for(int i = 1; i < n; ++i) {
int len = strlen(str[i]);
int p = root;
int tmp = 0;
fill(maxx, maxx + tot + 1, 0);
for(int j = 0; j < len; ++j) {
int x = str[i][j] - 'a';
if(node[p].ch[x]) {
++tmp;
p = node[p].ch[x];
} else {
while(p && node[p].ch[x] == 0)
p = node[p].fa;
if(p) {
tmp = node[p].val + 1;
p = node[p].ch[x];
} else {
p = root;
tmp = 0;
}
}
maxx[p] = max(maxx[p], tmp);
}
for(int j = 0; j < tot; ++j) {
int u = b[j];
minn[u] = min(minn[u], maxx[u]);
int v = node[u].fa;
maxx[v] = max(maxx[v], maxx[u]);
}
}
int ans = 0;
for(int i = 1; i <= tot; ++i)
ans = max(ans, minn[i]);
printf("%d\n", ans);
} int main() {
int n = 0;
while(scanf("%s", str[n]) != EOF) ++n;
sam.gao(n);
return 0;
}
spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)的更多相关文章
- SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机、状压DP)
手动博客搬家: 本文发表于20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680 人生第一道后缀自 ...
- 【刷题】SPOJ 1812 LCS2 - Longest Common Substring II
A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the s ...
- SPOJ 1812 LCS2 - Longest Common Substring II
思路 后缀自动机求多串的最长公共子串 对第一个建出后缀自动机,其他的在SAM上匹配,更新到一个节点的匹配长度最大值即可,最后对所有最大值取min得到一个节点的答案,对所有节点答案求max即可 然后注意 ...
- SPOJ LCS2 - Longest Common Substring II 后缀自动机 多个串的LCS
LCS2 - Longest Common Substring II no tags A string is finite sequence of characters over a non-emp ...
- SPOJ LCS2 Longest Common Substring II ——后缀自动机
后缀自动机裸题 #include <cstdio> #include <cstring> #include <iostream> #include <algo ...
- 【SPOJ 1812】Longest Common Substring II
http://www.spoj.com/problems/LCS2/ 这道题想了好久. 做法是对第一个串建后缀自动机,然后用后面的串去匹配它,并在走过的状态上记录走到这个状态时的最长距离.每匹配完一个 ...
- SPOJ:LCS2 - Longest Common Substring II
题面 给定一些字符串,求出它们的最长公共子串 输入格式 输入至多 \(10\) 行,每行包含不超过 \(100000\)个的小写字母,表示一个字符串 输出格式 一个数,最长公共子串的长度 若不存在最长 ...
- SPOJ LCS2 - Longest Common Substring II
LCS2 - Longest Common Substring II A string is finite sequence of characters over a non-empty finite ...
- spoj1812 LCS2 - Longest Common Substring II
地址:http://www.spoj.com/problems/LCS2/ 题面: LCS2 - Longest Common Substring II no tags A string is fi ...
随机推荐
- vue-router 基本使用(vue工程化)
(1)概念: 路由,其实就是指向的意思,当我点击页面上的home按钮时,页面中就要显示home的内容,如果点击页面上的about 按钮,页面中就要显示about 的内容.Home按钮 => h ...
- DHCP和PXE
继续学习,Let's go!DHCP和PXE都是什么呢?如果非科班出身,可能一脸懵逼,好多东西需要去学习了,真的,继续学吧,付出不一定会有回报,不付出肯定就是等死了,呵呵! 一.DHCP 真正需要手动 ...
- Nginx基础篇(2)- Nginx基本配置文件和变量详解
Nginx基本配置文件和变量详解 1. 基本配置文件 /etc/nginx/nginx.conf # nginx运行的用户 user nginx; # nginx进程数,建议设置为等于CPU总核心数. ...
- 零基础入门Python数据分析,只需要看懂这一张图,附下载链接!
摘要 在做数据分析的过程中,经常会想数据分析到底是什么?为什么要做数据数据分析?数据分析到底该怎么做?等这些问题.对于这些问题,一开始也只是有个很笼统的认识. 最近这两天,读了一下早就被很多人推荐的& ...
- 13-看图理解数据结构与算法系列(Trie树)
Trie树 Trie树,是一种搜索树,也称字典树或单词查找树,此外也称前缀树,因为某节点的后代存在共同的前缀.它的key都为字符串,能做到高效查询和插入,时间复杂度为O(k),k为字符串长度,缺点是如 ...
- 使用HTML,CSS快速导出数据到Excel
在应用中经常会遇到要从系统或数据库中导出数据平面文件,一般是导出到txt,csv或excel.txt和csv一般用在系统间的数据交换, 而excel一般有较好的显示效果,可以按照一定的模板导出,导出就 ...
- 配置bean
[bean配置] 在XML文件中通过bean节点来配置bean <!-- 配置bean class: bean的全类名,通过反射的方式在IOC容器中创建bean,所以要求bean中必须有无参的构 ...
- DD & E-app
DD & E-app 企业内部开发的E应用 前端 demo https://github.com/open-dingtalk docs https://open-doc.dingtalk.co ...
- hihoCoder#1120 小Hi小Ho的惊天大作战:扫雷·三
原题地址 看上去非常复杂, 实际上是这一系列最简单的一步,本质上是个搜索过程,相比于前一道题,可以不用策略三,而且题目的数据规模超级小,所以暴力搜索就能过. 把尚未确定的点放在一个unsettled列 ...
- 桐桐的糖果计划(vijos 1325)
背景 桐桐是一个快乐的小朋友,他生活中有许多许多好玩的事,让我们一起来看看吧…… 描述 桐桐很喜欢吃棒棒糖.他家处在一大堆糖果店的附近. 但是,他们家的区域经常出现塞车.塞人等情况,这导致他不得不等到 ...