手动博客搬家: 本文发表于20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680

人生第一道后缀自动机。

说实话SAM我还没学多么明白。

但是题还是要做的。

说起来这玩意真的很妙。可惜我智商低理解不了。

再次验证了代码能力菜到没边。hyw 30min写完我写2.5h.

题目链接 (洛谷)

https://www.luogu.org/problemnew/show/SP1812

题目大意

给\(n\)个长度为\(l_i\)的小写字母字符串,求它们的最长公共子串 (要求每个字符串都要出现。) \(n\le 10, l_i\le 10^5\)

题解

做法一 二分+hash判断。\(O(L\log L\times n)\), 据说会TLE.

做法二 后缀数组。不会。

做法三 后缀自动机。

用后缀自动机的有两种做法

做法一

首先考虑如何求两个串\(A,B\)的\(LCS\). 对\(A\)串建出后缀自动机,用\(B\)串在上面匹配。

匹配时从头到尾枚举\(B\)的每一个字符,记录当前\(A\)串后缀自动机的位置\(pos\)以及当前长度\(len\), 初始\(pos=rtn, len=0\) (\(rtn\)为根节点)

  1. 当前存在一条匹配边。即son[pos][str[i]]!=0, 则\(pos\)跳到\(son[pos][str[i]]\), \(len\)增加1即可。
  2. 当前不存在一条匹配边。即son[pos][str[i]]==0, 则\(pos\)从\(u\)开始向上跳,直到pos==0或者son[pos][str[i]]==0.分别对应第3和1种情况。此时\(len\)应置为\(Len[pos]\), \(Len[u]\)表示\(u\)状态表示的最长字符串。
  3. 如果u==0表明我们匹配到了自动机外面,则此时应重置\(pos=rtn,len=0\)

    这样我们可以处理\(n=2\)的情形。\(n>2\)?

    对于\(A_2, A_3,...,A_n\)分别跑一次,每一个节点记录一下匹配大小的最小值,然后求最大即可。每个点记录的最小值是因为要求这个子串同时是这\(n\)个串的公共部分,求最大是对于合法的状态求出最大值。

    做完了。?

    少了一步

    观察到\(n=2\)时\(A\)若长度较长的子串可以匹配,那么长度较短的子串也可以匹配。因此我们需要每做完一个串进行一遍更新:
if(fa[u]) mx[fa[u]] = max(mx[fa[u]],mx[u]);

做完了吗?

我们发现实际上对每个点还有限制,就是\(mx[u]\le len[u]\).

if(fa[u]) {mx[fa[u]] = max(mx[fa[u]],min(mx[u],len[fa[u]]));}

真·做完了。

代码

//Wrong Coding:
//pos = fa[pos]; curl = len[pos]; Wrong Order
//insertstr() len[np]=len[p]+1 Forgot
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define llong long long
using namespace std; const int N = 2e5;
const int M = 3e5;
const int S = 26;
int son[N+3][S+3];
int fa[N+3];
int len[N+3];
char a[N+3];
char b[N+3];
int buc[N+3];
int oid[N+3];
int ans[N+3];
int mx[N+3];
int sz[N+3];
int lpos,siz,rtn,lena; void insertstr(char ch)
{
int p = lpos,np; siz++; np = lpos = siz; sz[np] = 1; len[np] = len[p]+1;
for(; p && son[p][ch]==0; p=fa[p]) son[p][ch] = np;
if(p==0) {fa[np] = rtn;}
else
{
int q = son[p][ch];
if(len[p]+1==len[q]) {fa[np] = q;}
else
{
siz++; int nq = siz; len[nq] = len[p]+1;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq] = fa[q]; fa[np] = fa[q] = nq;
for(; p!=0 && son[p][ch]==q; p=fa[p]) son[p][ch] = nq;
}
}
} void prework()
{
for(int i=1; i<=siz; i++) buc[len[i]]++;
for(int i=1; i<=lena; i++) buc[i] += buc[i-1];
for(int i=siz; i>=1; i--) oid[buc[len[i]]--] = i;
for(int i=siz; i>=1; i--)
{
int pos = oid[i];
sz[fa[pos]] += sz[pos];
}
} void dfs(char str[],int lens)
{
int curl = 0,pos = rtn;
for(int i=1; i<=lens; i++)
{
while(pos && son[pos][str[i]-96]==0) {pos = fa[pos]; curl = len[pos];}
if(pos) {curl++; pos = son[pos][str[i]-96]; mx[pos] = max(mx[pos],curl);}
else {pos = rtn; curl = 0;}
}
for(int i=siz; i>=1; i--)
{
int u = oid[i];
if(fa[u]) {mx[fa[u]] = max(mx[fa[u]],min(mx[u],len[fa[u]]));}
ans[u] = min(ans[u],mx[u]);
mx[u] = 0;
}
} int main()
{
memset(ans,1,sizeof(ans));
siz = 1; rtn = 1; lpos = 1;
scanf("%s",a+1);
lena = strlen(a+1);
for(int i=1; i<=lena; i++) insertstr(a[i]-96);
prework();
while(scanf("%s",b+1)!=EOF)
{
int lenb = strlen(b+1);
dfs(b,lenb);
}
int fans = 0;
for(int i=1; i<=siz; i++) {if(ans[i]<=5e6) fans = max(fans,ans[i]);}
printf("%d\n",fans);
return 0;
}

完了?没有呢,还有做法二。

做法二

我们考虑这个题的一个加强版:每次给\(n\)个串的一个子集,询问这个子集内的串的\(LCS\). \(n\le 20, L\le 10^5, q\le 10^5\)

做法:\(n\)个串并起来建立广义\(SAM\). 然后每个状态记录一个\(n\)位二进制数。对于第\(i\)个串先在其所到达状态标记\(2^i\). 最后把标记沿着Parent树从下往上更新一下,然后统计出每一个子集的答案,然后再用每个集合的答案更新它的子集的答案(注意避免\(O(3^n)\)会\(TLE\))即可。

时间复杂度\(O(2^nn+nL)\)

可以参考GDOI2017微信这道题。见DC巨佬的博客:https://www.cnblogs.com/dcdcbigbig/p/10135665.html (引用已经过博主同意orz)

SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机、状压DP)的更多相关文章

  1. spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)

    spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 < ...

  2. 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 ...

  3. 【刷题】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 ...

  4. SPOJ 1812 LCS2 - Longest Common Substring II

    思路 后缀自动机求多串的最长公共子串 对第一个建出后缀自动机,其他的在SAM上匹配,更新到一个节点的匹配长度最大值即可,最后对所有最大值取min得到一个节点的答案,对所有节点答案求max即可 然后注意 ...

  5. SPOJ LCS2 Longest Common Substring II ——后缀自动机

    后缀自动机裸题 #include <cstdio> #include <cstring> #include <iostream> #include <algo ...

  6. 【SPOJ 1812】Longest Common Substring II

    http://www.spoj.com/problems/LCS2/ 这道题想了好久. 做法是对第一个串建后缀自动机,然后用后面的串去匹配它,并在走过的状态上记录走到这个状态时的最长距离.每匹配完一个 ...

  7. [SPOJ1812]Longest Common Substring II 后缀自动机 多个串的最长公共子串

    题目链接:http://www.spoj.com/problems/LCS2/ 其实两个串的LCS会了,多个串的LCS也就差不多了. 我们先用一个串建立后缀自动机,然后其它的串在上面跑.跑的时候算出每 ...

  8. SPOJ:LCS2 - Longest Common Substring II

    题面 给定一些字符串,求出它们的最长公共子串 输入格式 输入至多 \(10\) 行,每行包含不超过 \(100000\)个的小写字母,表示一个字符串 输出格式 一个数,最长公共子串的长度 若不存在最长 ...

  9. SPOJ LCS2 - Longest Common Substring II

    LCS2 - Longest Common Substring II A string is finite sequence of characters over a non-empty finite ...

随机推荐

  1. JDK框架简析--java.lang包中的基础类库、基础数据类型

    题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...

  2. vijos P1459车展

    P1459车展 Accepted 标签:数据结构 平衡树数据结构 堆重游SC theme Park     描述 遥控车是在是太漂亮了,韵韵的好朋友都想来参观,所以游乐园决定举办m次车展.车库里共有n ...

  3. 1360 xth 的玫瑰花

    1360 xth 的玫瑰花  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 这天是rabbit 的生日 ...

  4. 在Win7中修改 系统盘中 “系统” - “用户” 的环境变量映射关系

    1.在此列表中,选中对应登录帐号 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList 2.将Prof ...

  5. luogu1631 序列合并

    题目大意 有两个序列A,B,在A和B中各取一个数相加能得到$n^2$个和.求出这些和前n小的数字. 题解 首先这道题不可以用自己想的什么A序列B序列各两个指针的自己发明的模拟算法,用这样的算法只能是绝 ...

  6. LeetCode.884-两句话中不常见的单词(Uncommon Words from Two Sentences)

    这是悦乐书的第338次更新,第362篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第207题(顺位题号是884).我们给出了两个句子A和B.(一个句子是一串空格分隔的单词 ...

  7. [转]rdlc报表中表达式的使用--switch和IIF范例

    本文转自:http://hi.baidu.com/oypx1234/item/5b35dec4e03a3ad697445266 =Switch( Fields!MLWHLO.Value = " ...

  8. BZOJ 4808 二分图最大独立集

    思路: 棋盘是个二分图 那就把一个可以走的白点  向所有可以走的黑点连边 跑一个最大匹配   (匹配上了就代表这两个点不能共存) 最大独立集=sum-最大匹配 //By SiriusRen #incl ...

  9. A - Infinite Sequence

    Problem description Consider the infinite sequence of integers: 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2,  ...

  10. http接口 两种调用http接口的方法

    import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.NameValuePair; ...