【spoj1811 & spoj1812 - LCS1 & LCS2】sam
spoj1811 给两个长度小于100000的字符串 A 和 B,求出他们的最长公共连续子串。
先将串 A 构造为 SAM ,然后用 B 按如下规则去跑自动机。
用一个变量 lcs 记录当前的最长公共子串,初始化为0。
设当前状态结点为 p,要匹配的字符为 c,若 go[c] 中有边,说明能够转移状态,则转移并 lcs++;
若不能转移则将状态移动到 p 的 par ,如果仍然不能转移则重复该过程直到 p 回到根节点,并将 lcs 置为 0;
如果在上一个过程中进入了能够转移的状态,则设 lcs 为当前状态的 val。
为什么失配后要移向 par 呢?因为在状态 p 上失配说明该状态的 [min,max] 所表示字符串都不是 B 中的子串,但是比它们短的后缀仍有可能是 B 的子串,而 par 指针恰好指向了该状态的后缀。
spoj1812 要求多个串的最长公共子串,n<=100000,10个串。
本来想用广义sam,然后对每个点位压10位表示它能到哪些串,最后dfs一遍。
20*10^5=10^6个点,时间压得很紧直接超时。
参照上题做法,就把一个串A放进去,nlcs[x]维护当前串与A在自动机的x节点匹配的最大长度,lcs[x]维护前i个串。做完一个串后for一遍,x没有走到过的点lcs[x]=0,其余的lcs[x]=minn(lcs[x],nlcs[x]);
spoj1811
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std; const int N=*;
char a[N],b[N];
int al,bl,tot,last,son[N][],step[N],pre[N]; int maxx(int x,int y){return x>y ? x:y;} int add_node(int x)
{
step[++tot]=x;
return tot;
} void extend(int ch)
{
int p=last,np=add_node(step[p]+);
while(p && !son[p][ch]) son[p][ch]=np,p=pre[p];
if(!p) pre[np]=;
else
{
int q=son[p][ch];
if(step[q]==step[p]+) pre[np]=q;
else
{
int nq=add_node(step[p]+);
memcpy(son[nq],son[q],sizeof(son[q]));
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
while(son[p][ch]==q) son[p][ch]=nq,p=pre[p];
}
}
last=np;
} int main()
{
freopen("a.in","r",stdin);
// freopen("me.out","w",stdout);
memset(son,,sizeof(son));
memset(pre,,sizeof(pre));
memset(step,,sizeof(step));
tot=;add_node();last=;
scanf("%s%s",a+,b+);
al=strlen(a+),bl=strlen(b+);
for(int i=;i<=al;i++) extend(a[i]-'a'+);
int ch,x=,ans=,len=;
for(int i=;i<=bl;i++)
{
ch=b[i]-'a'+;
while(x && !son[x][ch]) x=pre[x],len=step[x];
if(x==) x=;
if(son[x][ch]) x=son[x][ch],len++; ans=maxx(ans,len);
}
printf("%d\n",ans);
return ;
}
spoj1812
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std; const int N=*;
char s[][N];
int n,tot,last,son[N][],step[N],pre[N],lcs[N],nlcs[N],l[];
bool vis[N];
struct node{
int x,y,next;
}a[*N]; int maxx(int x,int y){return x>y ? x:y;}
int minn(int x,int y){return x<y ? x:y;} int add_node(int x)
{
step[++tot]=x;lcs[tot]=x;
return tot;
} void extend(int ch)
{
int p=last,np=add_node(step[p]+);
while(p && !son[p][ch]) son[p][ch]=np,p=pre[p];
if(!p) pre[np]=;
else
{
int q=son[p][ch];
if(step[q]==step[p]+) pre[np]=q;
else
{
int nq=add_node(step[p]+);
memcpy(son[nq],son[q],sizeof(son[q]));
pre[nq]=pre[q];
pre[q]=pre[np]=nq;
while(son[p][ch]==q) son[p][ch]=nq,p=pre[p];
}
}
last=np;
} void solve(int id)
{
memset(nlcs,,sizeof(nlcs));
memset(vis,,sizeof(vis));
int x=,len=,ch;
for(int i=;i<=l[id];i++)
{
ch=s[id][i]-'a'+;
while(x && !son[x][ch])
{
x=pre[x],len=step[x],vis[x]=;
nlcs[x]=maxx(nlcs[x],len);
}
if(x==) x=,vis[]=;
if(son[x][ch]) x=son[x][ch],vis[x]=,len++;
nlcs[x]=maxx(nlcs[x],len);
}
for(int i=;i<=tot;i++)
if(!vis[i]) lcs[i]=;
else lcs[i]=minn(lcs[i],nlcs[i]);
} int main()
{
freopen("a.in","r",stdin);
// freopen("me.out","w",stdout);
memset(son,,sizeof(son));
memset(pre,,sizeof(pre));
memset(step,,sizeof(step));
tot=;add_node();last=;n=;
while(scanf("%s",s[++n]+)!=EOF)
{
l[n]=strlen(s[n]+);
}n--;
for(int i=;i<=l[];i++) extend(s[][i]-'a'+);
for(int i=;i<=n;i++) solve(i);
int ans=;
for(int i=;i<=tot;i++) ans=maxx(ans,lcs[i]);
printf("%d\n",ans);
return ;
}
【spoj1811 & spoj1812 - LCS1 & LCS2】sam的更多相关文章
- 【UOJ131/NOI2015D2T2-品酒大会】sam求后缀树
题目链接:http://uoj.ac/problem/131 题意:给出一个字符串,第i个字符对应的值为a[i], 对于i∈[0,n),求最长公共前缀大于等于i的字串对个数,并求这些字符串对开头对应值 ...
- SPOJ1811 && SPOJ1812
SPOJ1811 && SPOJ1812 LCS && LCS2 非常神奇的两道题... 题目大意: 给定n个字符串,求最长公共子串 做法1: 后缀数组: 把字符串连起 ...
- 【疯狂造轮子-iOS】JSON转Model系列之二
[疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...
- 【疯狂造轮子-iOS】JSON转Model系列之一
[疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...
- 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付
前言 最近有点空余时间,所以,就研究了一下APP支付.前面很早就搞完APP的微信支付了,但是由于时间上和应用上的情况,支付宝一直没空去研究.然后等我空了的时候,发现支付宝居然升级了支付逻辑,虽然目前还 ...
- 【AutoMapper官方文档】DTO与Domin Model相互转换(上)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- 【开源】分享2011-2015年全国城市历史天气数据库【Sqlite+C#访问程序】
由于个人研究需要,需要采集天气历史数据,前一篇文章:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子),介绍了基本的采集思路和核心代码,经过1个星期的采集,历史数据库 ...
- 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包
微信支付教程系列之现金红包 最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...
随机推荐
- Hibernate-ORM:11.Hibernate中的关联查询
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(i ...
- (4)分布式下的爬虫Scrapy应该如何做-规则自动爬取及命令行下传参
本次探讨的主题是规则爬取的实现及命令行下的自定义参数的传递,规则下的爬虫在我看来才是真正意义上的爬虫. 我们选从逻辑上来看,这种爬虫是如何工作的: 我们给定一个起点的url link ,进入页面之后提 ...
- 项目总结(二)->一些常用的工具浅谈
程序员是否应该沉迷于一个编程的世界,为了磨砺自己的编程技能而两耳不闻窗外事,一心只为写代码:还是说要做到各有涉猎,全而不精.关于这点每个人心中都有一套自己的工作体系和方法体系. 我一直认为,程序员你首 ...
- Windows自带的磁盘填充命令
一张不用了的SD卡要给别人,之前一直是手机使用的,担心有一些资料被恢复,想要将它内容清空.以前就知道数字公司有一个磁盘填充的工具,后来网上搜一搜发现Windows有一个自带的命令用于磁盘填充. 首先进 ...
- React错误总结解决方案(二)
1.React native: Cannot add a child that doesn't have a YogaNode or parent node 该错误一般是因为render方法中注释语句 ...
- DFS做题小结
一.深入理解DFS 采用递归写法 深度优先,思路就是沿着一条路一直走,直到走到死胡同,原路返回,返回到有多条道路的地方换其他路走.直到这条支路全部都访问过了,按照原路返回,回到起点,如果起点还有别的支 ...
- linux之shell脚本学习篇一
此文包含脚本服务请求,字符串截取,文件读写内容,打印内容换行. #!/bin/bashretMsg="";while read LINEdo echo "t ...
- jquery $.getJSON 注意细节
服务端: var json = "{\"title\": \"Recent Uploads tagged mountrainier\",\" ...
- Hibernate常用方法之_插入
1.使用session的save方法进行插入 public void saveUser(User user){ Session session = null; Transaction transact ...
- 【bzoj4627】[BeiJing2016]回转寿司 离散化+树状数组
题目描述 给出一个长度为n的序列,求所有元素的和在[L,R]范围内的连续子序列的个数. 输入 第一行包含三个整数N,L和R,分别表示寿司盘数,满意度的下限和上限. 第二行包含N个整数Ai,表示小Z对寿 ...