SPOJLCS Longest Common Substring
Longest Common Substring
给两个串A和B,求这两个串的最长公共子串。
no more than 250000
分析
参照OI wiki。
给定两个字符串 S 和 T ,求出最长公共子串,公共子串定义为在 S 和 T 中 都作为子串出现过的字符串 X 。
我们为字符串 S 构造后缀自动机。
我们现在处理字符串 T ,对于每一个前缀都在 S 中寻找这个前缀的最长后缀。换句话 说,对于每个字符串 T 中的位置,我们想要找到这个位置结束的 S 和 T 的最长公 共子串的长度。
为了达到这一目的,我们使用两个变量,当前状态 v 和 当前长度 l 。这两 个变量描述当前匹配的部分:它的长度和它们对应的状态。
一开始 v=t_0且 l=0 ,即,匹配为空串。
现在我们来描述如何添加一个字符 T[i] 并为其重新计算答案:
如果存在一个从 v 到字符 T[i] 的转移,我们只需要转移并让 l 自增一。
如果不存在这样的转移,我们需要缩短当前匹配的部分,这意味着我们需要按照以下后 缀链接进行转移:
v=link(v)
与此同时,需要缩短当前长度。显然我们需要将 l 赋值为 len(v) ,因为经过这个后缀链接后我们到达的状态所对应的最长字符串是一个子串。
如果仍然没有使用这一字符的转移,我们继续重复经过后缀链接并减小 l ,直到我们 找到一个转移或到达虚拟状态 -1 (这意味着字符 T[i] 根本没有在 S 中出现过, 所以我们设置 v=l=0 )。
问题的答案就是所有 l 的最大值。
这一部分的时间复杂度为 O(length(T)) ,因为每次移动我们要么可以使 l 增加一, 要么可以在后缀链接间移动几次,每次都减小 l 的值。
时间复杂度\(O(|S| + |T|)\)。
co int N=5e5;
namespace SAM
{
int tot,last;
int ch[N][26],fail[N]={-1},len[N];
void extend(int k)
{
int cur=++tot;
len[cur]=len[last]+1;
int p=last;
while(~p&&!ch[p][k])
{
ch[p][k]=cur;
p=fail[p];
}
if(p==-1)
fail[cur]=0;
else
{
int q=ch[p][k];
if(len[q]==len[p]+1)
fail[cur]=q;
else
{
int clone=++tot;
std::copy(ch[q],ch[q]+26,ch[clone]);
fail[clone]=fail[q],len[clone]=len[p]+1;
while(~p&&ch[p][k]==q)
{
ch[p][k]=clone;
p=fail[p];
}
fail[cur]=fail[q]=clone;
}
}
last=cur;
}
void ins(char s[],int n)
{
for(int i=0;i<n;++i)
extend(s[i]-'a');
}
void solve(char s[],int n)
{
int ans=0,v=0,l=0;
for(int i=0;i<n;++i)
{
int k=s[i]-'a';
if(ch[v][k])
v=ch[v][k],++l;
else
{
while(~v&&!ch[v][k])
v=fail[v];
if(v==-1)
v=l=0;
else
l=len[v]+1,v=ch[v][k];
}
ans=std::max(ans,l);
}
printf("%d\n",ans);
}
}
char buf[N];
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf("%s",buf);
SAM::ins(buf,strlen(buf));
scanf("%s",buf);
SAM::solve(buf,strlen(buf));
return 0;
}
【模板】后缀自动机
给定一个只包含小写字母的字符串S,
请你求出 S 的所有出现次数不为 1 的子串的出现次数乘上该子串长度的最大值。
对于100%的数据,|S|<=106
分析
学习资料:OI wiki,Menci's Blog,张天杨《后缀自动机及其应用》。
证明后缀自动机的状态数和转移数是线性的:
不同的状态的Right集只能是不相交或者真包含关系。
这种性质很容易让人想到树对不对,按照真包含关系做成树的话,大于一个元素的集合必定有大于等于两个儿子(保证了不会出现无用的链),只有一个元素的n个集合就是叶节点,所以总节点数小于等于\(2n-1\)。这样就说明状态数是线性的了。还差一点点,那就是转移数也是线性的。下面就来证明:
取自动机的一个有向的生成树,使得初始状态出发可以到达所有状态。对于一条不在树上的边,我们可以在树上从初始状态走到它的起点,然后经过它并走到终态,走的这条路径对应的一定是原串的一个后缀(初态→终态,后缀自动机)。所以每条非树边一定可以对应某些后缀,而不同的两条非树边对应的后缀不可能有重复(若重复,跑该后缀的时候状态转移不唯一),所以非树边数小于等于\(n-1\)。算上生成树上的边,我们得到:转移数小于等于\((2n-1-1)+(n-1)=3n-3\)。
我们令叶子节点的size=1.暴力建出parent树然后dfs,求出每个节点的right集合size,然后求len×size的最大值就行了。
时间复杂度:\(O(|S|)\)
co int N=2e6;
namespace SAM
{
int tot,last;
int ch[N][26],fail[N],len[N],siz[N];
void init()
{
tot=last=0;
fail[0]=-1,len[0]=0;
}
void extend(int k)
{
int cur=++tot;
len[cur]=len[last]+1,siz[cur]=1;
int p=last;
while(~p&&!ch[p][k])
{
ch[p][k]=cur;
p=fail[p];
}
if(p==-1)
fail[cur]=0;
else
{
int q=ch[p][k];
if(len[p]+1==len[q])
fail[cur]=q;
else
{
int clone=++tot;
std::copy(ch[q],ch[q]+26,ch[clone]);
fail[clone]=fail[q],len[clone]=len[p]+1;
while(~p&&ch[p][k]==q)
{
ch[p][k]=clone;
p=fail[p];
}
fail[q]=fail[cur]=clone;
}
}
last=cur;
}
void ins(char*s,int n)
{
for(int i=0;i<n;++i)
extend(s[i]-'a');
}
int nx[N],to[N];
ll ans;
void build()
{
for(int i=1;i<=tot;++i)
nx[i]=to[fail[i]],to[fail[i]]=i;
}
void dfs(int x)
{
for(int i=to[x];i;i=nx[i])
{
dfs(i);
siz[x]+=siz[i];
}
if(siz[x]>1)
ans=std::max(ans,(ll)siz[x]*len[x]);
}
void solve()
{
build();
dfs(0);
printf("%lld\n",ans);
}
}
char buf[N];
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
SAM::init();
scanf("%s",buf);
SAM::ins(buf,strlen(buf));
SAM::solve();
return 0;
}
SPOJLCS Longest Common Substring的更多相关文章
- SPOJ-LCS Longest Common Substring 【后缀自动机】
题目分析: 用没出现过的字符搞拼接.搞出right树,找right集合的最小和最大.如果最小和最大分居两侧可以更新答案. 代码: #include<bits/stdc++.h> using ...
- [SPOJ-LCS]Longest Common Substring
题目大意: 求两个字符串的LCS. 思路: 对其中一个字符串构建SAM,然后用另一个字符串在里面匹配,按照SAM的边一直往下走,匹配到的连续的字符数就是公共字串的长度. #include<str ...
- Longest Common Substring II SPOJ - LCS2 (后缀自动机)
Longest Common Substring II \[ Time Limit: 236ms\quad Memory Limit: 1572864 kB \] 题意 给出\(n\)个子串,要求这\ ...
- SPOJ LCS2 - Longest Common Substring II
LCS2 - Longest Common Substring II A string is finite sequence of characters over a non-empty finite ...
- LintCode Longest Common Substring
原题链接在这里:http://www.lintcode.com/en/problem/longest-common-substring/# 题目: Given two strings, find th ...
- Longest Common Substring
Given two strings, find the longest common substring. Return the length of it. Example Given A = &qu ...
- 【SPOJ】1812. Longest Common Substring II(后缀自动机)
http://www.spoj.com/problems/LCS2/ 发现了我原来对sam的理解的一个坑233 本题容易看出就是将所有匹配长度记录在状态上然后取min后再对所有状态取max. 但是不要 ...
- hdu 1403 Longest Common Substring(最长公共子字符串)(后缀数组)
http://acm.hdu.edu.cn/showproblem.php?pid=1403 Longest Common Substring Time Limit: 8000/4000 MS (Ja ...
- 后缀自动机(SAM):SPOJ Longest Common Substring II
Longest Common Substring II Time Limit: 2000ms Memory Limit: 262144KB A string is finite sequence of ...
随机推荐
- dubbo应用
一.安装配置 cd /usr/local/ wget http://www.apache.org/dist/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar. ...
- 为JAXB和response设置编码,解决wechat4j中文乱码
如果有哪一个做程序员的小伙伴说自己没有遇到中文乱码问题,我是不愿意相信的.今天在做微信订阅号的智能回复时,又一时迷乱的跳进了中文乱码这个火坑.刚解决问题时,都欢呼雀跃了,完全忘记了她曾经带给我的痛苦. ...
- MYSQL的基本语句——思维导图
如图 思维导图图片链接 http://www.edrawsoft.cn/viewer/public/s/a1718332616630 有道云笔记图片链接 http://note.youdao.com/ ...
- Hibernate -- 配置c3p0连接池, 事务隔离级别, 管理session
知识点1:配置c3p0连接池(了解) * 引入c3p0-0.9.1.jar * 在hibernate.cfg.xml文件中增加如下配置 <!-- C3P0连接池设定--> <!-- ...
- Divide two numbers,两数相除求商,不能用乘法,除法,取模运算
问题描述:求商,不能用乘法,除法,取模运算. 算法思路:不能用除法,那只能用减法,但是用减法,超时.可以用位移运算,每次除数左移,相当于2倍. public class DividTwoInteger ...
- Spark- SparkSQL中 Row.getLong 出现NullPointerException错误的处理方法
在SparkSQL中获取Row的值,而且Row的字段允许null时,在取值的时候取到null赋值给新的变量名会报NullPointerException错误, 可以先用row.isNullAt(ind ...
- NLP(三)_统计语言模型
概念 统计语言模型:是描述自然语言内在的规律的数学模型.广泛应用于各种自然语言处理问题,如语音识别.机器翻译.分词.词性标注,等等.简单地说,语言模型就是用来计算一个句子的概率的模型 即P(W1,W2 ...
- pOJ-1061 exgcd求同余方程组
链接 就是求(m-n)*a+b*l=y-x, 类似于求解a*x+b*y=c,r=gcd(a,b),当c%r==0时有解,用exgcd求出a*x+b*y=gcd(a,b)的解,然后x*c/gcd(a,b ...
- 第七届蓝桥杯C-B-10-最大比例/gcd变形
最大比例 X星球的某个大奖赛设了M级奖励.每个级别的奖金是一个正整数.并且,相邻的两个级别间的比例是个固定值.也就是说:所有级别的奖金数构成了一个等比数列.比如:16,24,36,54其等比值为:3/ ...
- HDU-1007-最小公共点对
http://acm.hdu.edu.cn/showproblem.php?pid=1007 Quoit Design Time Limit: 10000/5000 MS (Java/Others) ...