spoj 1812 LCS2(SAM+DP)

Longest Common Substring II

Time Limit: 236MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

Description

A string is finite sequence of characters over a non-empty finite set Σ.

In this problem, Σ is the set of lowercase letters.

Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.

Now your task is a bit harder, for some given strings, find the length of the longest common substring of them.

Here common substring means a substring of two or more strings.

Input

The input contains at most 10 lines, each line consists of no more than 100000 lowercase letters, representing a string.

Output

The length of the longest common substring. If such string doesn‘t exist, print "0" instead.

Example

Input:
alsdfkjfjkdsal
fdjskalajfkdsla
aaaajfaaaa

Output:
2

【题意】

  求若干个串的最长公共子串。

【思路】

SAM+DP

先拿个串建个SAM,然后用后面的串匹配,SAM中每个结点维护两个信息:mx表示与当前串匹配到该结点的最大长度,mn表示与前几个串匹配到该结点的最小长度。最后ans取所有节点mn的最大值。

注意mn[p]初始化为l[p]

cxlove:出现次数向父亲传递,接收串数从儿子获取

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4
 5 const int N = 5*1e5+10;
 6
 7 char s[N];
 8 int sz,last,root,l[N],ch[N][26],fa[N],mn[N],mx[N];
 9 int b[N],cnt[N];
10 void add(int x) {
11     int c=s[x]-‘a‘;
12     int p=last,np=++sz; last=np;
13     l[np]=mn[np]=x+1;
14     for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
15     if(!p) fa[np]=root;
16     else {
17         int q=ch[p][c];
18         if(l[p]+1==l[q]) fa[np]=q;
19         else {
20             int nq=++sz; l[nq]=mn[nq]=l[p]+1;
21             memcpy(ch[nq],ch[q],sizeof(ch[q]));
22             fa[nq]=fa[q];
23             fa[np]=fa[q]=nq;
24             for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
25         }
26     }
27 }
28
29 int main() {
30     root=last=++sz;
31     scanf("%s",s);
32     int len=strlen(s);
33     for(int i=0;i<len;i++) add(i);
34     for(int i=1;i<=sz;i++) cnt[l[i]]++;
35     for(int i=1;i<=len;i++) cnt[i]+=cnt[i-1];
36     for(int i=1;i<=sz;i++) b[cnt[l[i]]--]=i;
37     while(scanf("%s",s)==1) {
38         int p=root; len=0;
39         for(int i=0;s[i];i++) {
40             int c=s[i]-‘a‘;
41             if(ch[p][c]) { len++; p=ch[p][c]; }
42             else {
43                 while(p&&!ch[p][c]) p=fa[p];
44                 if(!p) { len=0; p=root; }
45                 else { len=l[p]+1; p=ch[p][c]; }
46             }
47             if(len>mx[p]) mx[p]=len;
48         }
49         for(int i=sz;i;i--) {
50             p=b[i];
51             if(mx[p]<mn[p]) mn[p]=mx[p];
52             if(fa[p] && mx[fa[p]]<mx[p]) mx[fa[p]]=mx[p];
53             mx[p]=0;
54         }
55     }
56     int ans=0;
57     for(int i=1;i<=sz;i++)
58         if(mn[i]>ans) ans=mn[i];
59     printf("%d",ans);
60     return 0;
61 }
时间: 2024-10-05 09:41:03

spoj 1812 LCS2(SAM+DP)的相关文章

CF1120 C. Compress String(SAM+DP)

有方程dp[i]=min(dp[i-1]+A,dp[j]+B):如果s[j+1,i]在s[i,j]中出现,所以我们就是要知道每个子串在s出现的第一个位置,这个可以hash实现或者sam实现. pos[i][j]表示s[i,j]对应的sam的位置,occ[],表示第一次出现的位置. #include<bits/stdc++.h> #define ll long long #define rep2(i,a,b) for(int i=a;i>=b;i--) #define rep(i,a,b)

SPOJ MYQ10 10649. Mirror Number (数位dp)

SPOJ MYQ10 10649. Mirror Number (数位dp) ACM 题目地址:SPOJ MYQ10 Mirror Number 题意: 求[a,b]中镜像回文的个数. 0 <= a<=b <= 10^44 分析: 看到题目和数据范围就知道是数位dp了. 很明显镜像回文只有0,1,8,跟回文的一题一样,在dfs的时候得开个辅助数组记录前面已经选择的数字. 注意还得去掉前导0. 代码: /* * Author: illuz <iilluzen[at]gmail.com

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]

LightOJ 1205 - Palindromic Numbers (数位dp)

LightOJ 1205 - Palindromic Numbers (数位dp) ACM 题目地址:SPOJ MYQ10 Mirror Number 题意: 求[a,b]中回文的个数. 分析: 是SPOJ MYQ01的简单版...其实有非递归方法的. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * Blog: http://blog.csdn.net/hcbbt * File: 1205.cpp * Create Date: 2014-08-

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

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS几乎相同的做法 把当中一个A建后缀自己主动机 考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n -

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

HDU 4960 (水dp)

Another OCD Patient Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xi

hdu 2089 不要62 (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 思路:用变量记录吉利数,和最高位为2的吉利数还有不是吉利数的个数... code: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10][3]; //dp[i][j] ,i表示位数,j表示状态<pre name="code"

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&