公共串

Time Limit: 3 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

Description

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

Input

  文件的第一行是整数 n ,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

Output

  仅一行,一个整数,最长公共子串的长度。

Sample Input

  3
  abcb
  bca
  acbc

Sample Output

  2

HINT

  2 <= n <= 5

Solution

  因为要求所有串的最长公共子串,所以我们运用SAM,先对第一个串(基本串)构建一个SAM,然后用后面的串匹配即可。

  记录 L[i] 表示当前串和基本串在 i 这个状态匹配的最长长度。显然,一个状态对答案的贡献是所有串和基本串匹配时 L[i] 的最小值

  然后取一个最大值即可。

Code

  1. #include<iostream>
  2. #include<string>
  3. #include<algorithm>
  4. #include<cstdio>
  5. #include<cstring>
  6. #include<cstdlib>
  7. #include<cmath>
  8. using namespace std;
  9.  
  10. const int ONE=;
  11. const int INF=;
  12.  
  13. int T,n;
  14. char str[ONE];
  15. int ans[ONE], q[ONE], L[ONE];
  16. int len[ONE], a[ONE][], fa[ONE], v[ONE];
  17. int last, cnt;
  18. int Ans;
  19.  
  20. int get()
  21. {
  22. int res=,Q=;char c;
  23. while( (c=getchar())< || c> )
  24. if(c=='-')Q=-;
  25. res=c-;
  26. while( (c=getchar())>= && c<= )
  27. res=res*+c-;
  28. return res*Q;
  29. }
  30.  
  31. struct SAM
  32. {
  33. SAM() {last = cnt = ;}
  34. void Add(int c)
  35. {
  36. int x = last, New = last = ++cnt;
  37. len[New] = len[x] + ;
  38. while(x && !a[x][c]) a[x][c] = New, x = fa[x];
  39. if(!x) {fa[New] = ; return;}
  40.  
  41. int q = a[x][c];
  42. if(len[x] + == len[q]) fa[New] = q;
  43. else
  44. {
  45. int Nq = ++cnt; len[Nq] = len[x] + ;
  46. memcpy(a[Nq], a[q], sizeof(a[q]));
  47. fa[Nq] = fa[q];
  48. fa[New] = fa[q] = Nq;
  49. while(a[x][c] == q) a[x][c] = Nq, x = fa[x];
  50. }
  51. }
  52.  
  53. void Pre()
  54. {
  55. for(int i=; i<=cnt; i++) v[len[i]]++;
  56. for(int i=; i<=cnt; i++) ans[i] = len[i];
  57. for(int i=; i<=n; i++) v[i] += v[i-];
  58. for(int i=cnt; i>=; i--) q[v[len[i]]--] = i;
  59. }
  60. };
  61. SAM S;
  62.  
  63. void Check()
  64. {
  65. memset(L, , sizeof(L));
  66. n = strlen(str+);
  67. int x = , record = ;
  68. for(int i=; i<=n; i++)
  69. {
  70. int c = str[i]-'a'+;
  71. while(x && !a[x][c]) x = fa[x];
  72. if(!x) {x = ; record = ; continue;}
  73. record = min(record, len[x]) + ;
  74. x = a[x][c];
  75. L[x] = max(L[x], record);
  76. }
  77.  
  78. for(int i=cnt; i>=; i--)
  79. L[fa[q[i]]] = max(L[fa[q[i]]], L[q[i]]);
  80. for(int i=; i<=cnt; i++)
  81. ans[i] = min(ans[i], L[i]);
  82. }
  83.  
  84. int main()
  85. {
  86. T = get(); T --;
  87. scanf("%s", str+); n = strlen(str+);
  88. for(int i=; i<=n; i++) S.Add(str[i]-'a'+);
  89. S.Pre();
  90.  
  91. while(T--)
  92. {
  93. scanf("%s", str+);
  94. Check();
  95. }
  96.  
  97. for(int i=; i<=cnt; i++)
  98. Ans = max(Ans, ans[i]);
  99.  
  100. printf("%d",Ans);
  101. }

【BZOJ2946】公共串 [SAM]的更多相关文章

  1. [BZOJ2946] [Poi2000]公共串解题报告|后缀数组

    给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 单词个数<=5,每个单词长度<=2000     尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA... (其实是不 ...

  2. 【BZOJ2946】公共串(后缀数组)

    [BZOJ2946]公共串(后缀数组) 题面 权限题... 只有CJOJ题面啦 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: 读入单词,计算最长公共子串的 ...

  3. 【BZOJ2946】[Poi2000]公共串 后缀数组+二分

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

  4. 【BZOJ 2946】 2946: [Poi2000]公共串 (SAM)

    2946: [Poi2000]公共串 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1063  Solved: 469 Description      ...

  5. 【bzoj2946】[Poi2000]公共串 后缀自动机

    [Poi2000]公共串 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1386  Solved: 620[Submit][Status][Discus ...

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

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

  7. BZOJ 2946 [Poi2000]公共串 (二分+Hash/二分+后缀数组/后缀自动机)

    求多串的最长公共字串. 法1: 二分长度+hash 传送门 法2: 二分+后缀数组 传送门 法3: 后缀自动机 拿第一个串建自动机,然后用其他串在上面匹配.每次求出SAM上每个节点的最长匹配长度后,再 ...

  8. BZOJ 2946: [Poi2000]公共串

    2946: [Poi2000]公共串 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 342[Submit][Status][D ...

  9. BZOJ 2946: [Poi2000]公共串( 后缀自动机 )

    一个串建后缀自动机, 其他串在上面跑, 然后用当前串跑的去更新全部 ------------------------------------------------------------------ ...

随机推荐

  1. autoCAD 2008 Win7 64位, win8 64位 安装 燕秀工具箱 yanxiu.cui 文件下载

    Win7 64位, win8 64位 安装 燕秀工具箱 , 提示没有权限. 网站上下载燕秀工具箱, 安装后. 提示权限不够. 解决办法如下; 1. CAD, 权限修改. 2. 下载 yanxiu.cu ...

  2. TCP系列23—重传—13、RACK重传

    一.RACK概述 RACK(Recent ACKnowledgment)是一种新的基于时间的丢包探测算法,RACK的目的是取代传统的基于dupthresh门限的各种快速重传及其变种.前面介绍的各种基于 ...

  3. lol人物模型提取(三)

      提取出来的lol人物模型能让你知道一些有趣的信息,比如说给英雄量个身高啥的.   经测量,佐伊的身高应大于1m60,比想象中的着实高不少啊.   然后还应该把这个模型镜像对称一下,在3dsmax里 ...

  4. PAT 甲级 1032 Sharing

    https://pintia.cn/problem-sets/994805342720868352/problems/994805460652113920 To store English words ...

  5. InnoDB,select为啥会阻塞insert?

    MySQL的InnoDB的细粒度行锁,是它最吸引人的特性之一. 但是,如<InnoDB,5项最佳实践>所述,如果查询没有命中索引,也将退化为表锁. InnoDB的细粒度锁,是实现在索引记录 ...

  6. bzoj4278[ONTAK2015]Tasowanie & bzoj1692[USACO 2007Dec]队列变换(Best Cow Line) 贪心正确性证明

    做法网上到处都有就不说了. 这题其实是之前做的….不过由于人太傻现在才想明白比较字典序进行贪心的正确性…. 方便起见,在两个串的最右端都加上很大但不相同的字符,避免第lcp+1个字符不存在的边界. 如 ...

  7. C# 连接Oracle数据库以及一些简单的操作

    拖了很久今天终于在博客园写了自己第一篇随笔: 话不多说,我们直接进入正题: 1.连接数据库 using (OracleConnection conn = new OracleConnection(&q ...

  8. 51nod 1286 三段子串(树状数组+拓展kmp)

    题意: 给定一个字符串S,找到另外一个字符串T,T既是S的前缀,也是S的后缀,并且在中间某个地方也出现一次,并且这三次出现不重合.求T最长的长度. 例如:S = "abababababa&q ...

  9. [洛谷P3174][HAOI2009]毛毛虫

    题目大意:给一棵树,求其中最大的“毛毛虫”,毛毛虫的定义是一条链上分出几条边 题解:把每个点的权值定义为它的度数减一,跑带权直径即可,最后答案加二 卡点:无 C++ Code: #include &l ...

  10. ARC072E Alice in linear land

    ---题面--- 题解: 首先我们要观察到一个性质,因为在固定的起始距离下,经过固定的操作,最后所在的位置是固定的,我们设经过操作1 ~ i之后所在的地方距离终点为d[i]. 那么如果女巫可以修改第i ...