给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
单词个数<=5,每个单词长度<=2000
  
 
  尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA...
  (其实是不知道应该怎么用SAM做...
  对于后缀数组而言,多个字符串的公共子串与两个处理起来并没有什么区别
  只要在中间加一些没有用的字符,将多个字符串拼成一个字符串
  然后二分答案,对于一个长度L,在一组除了开头其他height都>=L的区间中如果每个字符串的位置都出现过就可以
  
  应该是第二次这么解决一道公共串的题了..
  然后发现了一些新的东西..
  比如之前处理没有的字符串处理了很久,这次我直接在每两个字符串间添加不同的字符
  理由很简单:
  对于原来就在同一个字符串中的两个后缀,它们后面的字符相同,但是由于长度不同,所以没有影响
  即匹配的时候谁先接触到无用字符谁就更小一些,符合我们的愿望
  而对于原来不在一个字符串中的两个后缀,如果他们后面的字符相同,再加上原本的长度也一样
  匹配的时候height数组算出的答案就会比实际的长度要大
  然而我们现在填了不同的字符就可以很好地避免掉这个问题
 
  不知道为什么...我的SA很长...
  不过无所谓只要好理解不用背代码...长一点也只是敲敲键盘的问题...
  这里是用SAM解这道题的方法
 
 
 program bzoj2946;
const maxn = ;
var b,sa,rank,tmp,a,pos,height:array[-..maxn]of longint;
vis,l,r:array[-..]of longint;
maxlen,n,m,i,j,lx,rx,mid,ans:longint;
s:ansistring;
ss:array[-..]of ansistring; function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end; procedure Suffix_Array;
var i,j,p,sz,v0,v1,v01,v00:longint;
begin
sz:=max(,length(s));
for i:= to sz do b[i]:=;
for i:= to m- do inc(b[a[i]]);
for i:= to m- do rank[i]:=a[i];
for i:= to sz do inc(b[i],b[i-]);
for i:=m- downto do
begin
dec(b[rank[i]]);
sa[b[rank[i]]]:=i;
end;
j:=;
while j<=m do
begin
p:=;
for i:=m-j to m- do
begin
tmp[p]:=i;inc(p);
end;
for i:= to m- do if sa[i]-j>= then
begin
tmp[p]:=sa[i]-j;inc(p);
end;
for i:= to sz do b[i]:=;
for i:= to m- do inc(b[rank[i]]);
for i:= to sz do inc(b[i],b[i-]);
for i:=m- downto do
begin
dec(b[rank[tmp[i]]]);
sa[b[rank[tmp[i]]]]:=tmp[i];
end;
tmp[sa[]]:=;p:=;
for i:= to m- do
begin
v0:=sa[i-];v1:=sa[i];
if v0+j<m then v00:=rank[v0+j] else v00:=-;
if v1+j<m then v01:=rank[v1+j] else v01:=-;
if (rank[v0]=rank[v1])and(v00=v01) then tmp[sa[i]]:=p else
begin
inc(p);tmp[sa[i]]:=p;
end;
end;
for i:= to m- do rank[i]:=tmp[i];
j:=j << ;
end;
end; function compare(i,j,x:longint):longint;
begin
while (i+x-<m)and(j+x-<m)and(a[i+x-]=a[j+x-]) do inc(x);
exit(x-);
end; procedure calc_height;
var i:longint;
begin
if rank[]= then height[]:= else height[]:=compare(,sa[rank[]-],);
for i:= to m- do
if rank[i]= then height[i]:= else height[i]:=compare(i,sa[rank[i]-],max(height[i-],));
end; function solve(x:longint):boolean;
var i,j,k:longint;
begin
for i:= to n do vis[i]:=-;
i:=;
while i<m do
begin
j:=i+;
while (j<m)and(height[sa[j]]>=x) do inc(j);
for k:=i to j- do vis[pos[sa[k]]]:=i;
for k:= to n do if vis[k]<>i then break;
if vis[k]=i then exit(true);
i:=j;
end;
exit(false);
end; begin
readln(n);s:='';maxlen:=;
for i:= to n do
begin
readln(ss[i]);
if length(ss[i])>maxlen then maxlen:=length(ss[i]);
end;
maxlen:= << (trunc(ln(maxlen)/ln())+);
fillchar(pos,sizeof(pos),);
for i:= to n do
begin
l[i]:=length(s)+;
s:=s+ss[i];
r[i]:=length(s);
for j:=l[i] to r[i] do pos[j-]:=i;
for j:= to maxlen do s:=s+chr(i);
end;
m:=length(s);
for i:= to m- do a[i]:=ord(s[i+]);
Suffix_Array;
Calc_Height;
Lx:=;Rx:=maxlen;ans:=;
while Lx<=Rx do
begin
mid:=(Lx+Rx) >> ;
if solve(mid) then
begin
ans:=mid;Lx:=mid+;
end else Rx:=mid-;
end;
writeln(ans);
end.

[BZOJ2946] [Poi2000]公共串解题报告|后缀数组的更多相关文章

  1. [BZOJ2946][Poi2000]公共串解题报告|后缀自动机

    鉴于SAM要简洁一些...于是又写了一遍这题... 不过很好呢又学到了一些新的东西... 这里是用SA做这道题的方法 首先还是和两个字符串的一样,为第一个字符串建SAM 然后每一个字符串再在这个SAM ...

  2. [bzoj2946][Poi2000]公共串_后缀数组_二分

    公共串 bzoj-2946 Poi-2000 题目大意:给定$n$个字符串,求他们的最长公共子串. 注释:$1\le n\le 5$,$1\le minlen<maxlen\le 2000$. ...

  3. BZOJ2946 Poi2000 公共串 【后缀自动机】

    Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单词 l 计算最长公共子串的长度 l 输出结果 Input 文件的第一行是整数 n,1<=n& ...

  4. [codevs3160]最长公共子串解题报告|后缀自动机

    给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 样例就觉得不能更眼熟啊...好像之前用后缀数组做过一次 然后发现后缀自动机真的好好写啊...(当然当时学后缀数组的时候也这么认为... 这 ...

  5. [BZOJ2754] [SCOI2012]喵星球上的点名解题报告|后缀数组

    a180285幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣.   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成.喵星球上的老师会选择M个串来点名,每次读出一个串的 ...

  6. [BZOJ3238][Ahoi2013]差异解题报告|后缀数组

    Description 先分析一下题目,我们显然可以直接算出sigma(len[Ti]+len[Tj])的值=(n-1)*n*(n+1)/2 接着就要去算这个字符串中所有后缀的两两最长公共前缀总和 首 ...

  7. bzoj2946 [Poi2000]公共串(SA,SAM)

    [题意] 多串求LCS.   [思路]   主要是想找一下SAM的优越感 :) velui good 后缀数组划分height需要注意不少细节 <_<,然后不停debug   [代码]   ...

  8. BZOJ2946 [Poi2000]公共串(后缀自动机)

    Description          给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单词 l        计算最长公共子串的长度 l        输 ...

  9. SPOJ1812: LCS2 - Longest Common Substring II & BZOJ2946: [Poi2000]公共串

    [传送门:SPOJ1811&BZOJ2946] 简要题意: 给出若干个字符串,求出这些字符串的最长公共子串 题解: 后缀自动机 这两道题的区别只是在于一道给出了字符串个数,一个没给,不过也差不 ...

随机推荐

  1. 纯js生成QRCode

    纯js,不依赖jquery,非常好用,废话不多说,直接上代码! <!DOCTYPE html> <html> <head> <meta charset=&qu ...

  2. 【vim环境配置】解决ubuntu上 由YouCompleteMe插件配置不当引起的 自动补全失效的问题

    背景: 由于不可抗拒的原因,学习环境由之前centos的一台机器上,变成了ubuntu的一台机器上.因此,需要在新的ubuntu的机器上再配置一次vim环境.算起来这已经是第三次配置vim环境了(ma ...

  3. Anytime项目开发记录2

    注册,登陆于密码找回.这是这次记录的主要内容. 首先,我们来看类图: 因为一直在改,所以与第二篇介绍项目框架时的图会有一些不一样. 代码都是非常简单的. 由于在注册和登陆这里,需要弹出一些对话框告诉用 ...

  4. 汇编指令MOVSX与MOVZX

    MOVSX 操作数A ,操作数B MOVZX 操作数A ,操作数B 相同点:操作数B 空间必须小于 操作数A 1.格式与MOV基本相同 2.能完成小存储单元向大存储单元的数据传送 比如 movsx e ...

  5. beanshell引用参数化数据

    步骤: 1.添加参数化组件CSV Data Set  Config: 2.添加beanshell preprocessor,引用变量: 验证: 2个线程,迭代2次,分别取了4个不同的值.

  6. react实现网站换肤功能

    一.目标   提供几种主题色给用户选择,然后根据用户的选择改变应用的主题色: 二.实现原理   1.准备不同主题色的样式文件:   2.将用户的选择记录在本地缓存中:   3.每次进入应用时,读取缓存 ...

  7. tensorflow学习笔记(2)-反向传播

    tensorflow学习笔记(2)-反向传播 反向传播是为了训练模型参数,在所有参数上使用梯度下降,让NN模型在的损失函数最小 损失函数:学过机器学习logistic回归都知道损失函数-就是预测值和真 ...

  8. wangEditor编辑器中解析html图文信息问题

    在JS中,有一种方法:innerHTML 属性设置或返回表格行的开始和结束标签之间的 HTML. 也就是说,我们可以利用这个属性,把字符串转换为html代码,这样就可以被解析了. 其次,我们是需要在页 ...

  9. PhoneGap & HTML5 学习资料网址

    PhoneGap 与 Application Cache应用缓存  http://www.html5cn.org/forum.php?mod=viewthread&tid=40272 加速We ...

  10. Redis数据类型及操作详解

    Redis数据库,是nosql的一种.与传统关系型数据库(如mysql.sqlserver等)相比,他在处理大数据量上相当有优势,扩展性和可用性高,这是传统型数据库所达不到的. Redis是一个key ...