codevs 3160 最长公共子串

3160 最长公共子串

时间限制: 2 s

空间限制: 128000 KB

题目等级 : 大师 Master

题解

查看运行结果

题目描述 Description

给出两个由小写字母组成的字符串,求它们的最长公共子串的长度。

输入描述 Input Description

读入两个字符串

输出描述 Output Description

输出最长公共子串的长度

样例输入 Sample Input

yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother

样例输出 Sample Output

27

数据范围及提示 Data Size & Hint

单个字符串的长度不超过100000
  

最近迷上字符串来hhhhh
这个题的解法比较巧妙,我们把两个字符串中间随便加一个不会出现的字符然后连起来做后缀数组,求出height之后,
如果sa[i]和sa[i-1]不在同一字符串中,我们就可以用height[i]更新答案。

这样得到的答案显然是最优的,因为求lcp是在height上的rmq,而显然rank不相邻的两个位置答案不会比相邻的更优。

#include<bits/stdc++.h>
#define ll long long
#define maxn 200005
using namespace std;
char s[maxn];
int sa[maxn],sax[maxn];
int rank[maxn<<1],rankx[maxn];
int cc[maxn],height[maxn];
int n,m,len,ans=0,sec[maxn];

inline int pos(int x){
    return x<n;
}

inline void get_height(){
    for(int i=0;i<len;i++) cc[s[i]]++;
    for(int i=1;i<=500;i++) cc[i]+=cc[i-1];
    for(int i=0;i<len;i++) sa[cc[s[i]]--]=i;
    for(int i=1;i<=len;i++){
        rank[sa[i]]=i;
        if(i>1&&s[sa[i]]==s[sa[i-1]]) rank[sa[i]]=rank[sa[i-1]];
    }

    int k=1;
    while(k<len){
        memset(cc,0,sizeof(cc));
        for(int i=0;i<len;i++) cc[sec[i]=rank[i+k]]++;
        for(int i=len-1;i>=0;i--) cc[i]+=cc[i+1];
        for(int i=0;i<len;i++) sax[cc[sec[i]]--]=i;

        memset(cc,0,sizeof(cc));
        for(int i=0;i<len;i++) cc[rank[i]]++;
        for(int i=1;i<=len;i++) cc[i]+=cc[i-1];
        for(int i=1;i<=len;i++) sa[cc[rank[sax[i]]]--]=sax[i];

        for(int i=1;i<=len;i++){
            rankx[sa[i]]=i;
            if(i>1&&rank[sa[i]]==rank[sa[i-1]]&&sec[sa[i]]==sec[sa[i-1]]) rankx[sa[i]]=rankx[sa[i-1]];
        }

        for(int i=0;i<len;i++) rank[i]=rankx[i];
        k<<=1;
    }

    int now=0,j,mx;
    for(int i=0;i<len;i++){
        if(rank[i]==1){
            now=height[rank[i]]=0;
            continue;
        }
        if(now) now--;
        j=sa[rank[i]-1],mx=max(j,i);
        while(mx+now<len&&s[i+now]==s[j+now]) now++;
        height[rank[i]]=now;
    }

}

int main(){
    scanf("%s",s);
    n=strlen(s);
    s[n]=‘~‘;
    scanf("%s",s+n+1);
    len=strlen(s);

    get_height();
    for(int i=2;i<=len;i++) if(pos(sa[i])^pos(sa[i-1])) ans=max(ans,height[i]);
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/JYYHH/p/8286648.html

时间: 2024-10-17 22:01:36

codevs 3160 最长公共子串的相关文章

codevs 3160 最长公共子串(SAM)

3160 最长公共子串 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Output Description 输出最长公共子串的长度 样例输入 Sample Input yeshowmuchiloveyoumydearmotherreallyicannotbelieveityeaphowmuchiloveyoumydearmother 样例输出 Sample Output 27

3160 最长公共子串

3160 最长公共子串 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Output Description 输出最长公共子串的长度 样例输入 Sample Input yeshowmuchiloveyoumydearmotherreallyicannotbelieveityeaphow

【wikioi】3160 最长公共子串(后缀自动机)

http://codevs.cn/problem/3160/ sam的裸题...(之前写了spoj上另一题sam的题目,但是spoj被卡评测现在还没评测完QAQ打算写那题题解时再来详细介绍sam的....那就再等等吧. 求两个串的lcs话,就是先建立a串的sam,然后用b的字串去匹配a中. 因为sam中每个状态的len对应最长子串,因此自动机不断trans匹配时,如果没找到下一个点,那么在parent树的祖先中找是否还有子串可以更新(因为祖先的max比这个节点小,且都包含当前状态的right,所

【Codevs3160】最长公共子串

当然先虐SAM裸题QwQ 3160 最长公共子串 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Output Description 输出最长公共子串的长度 样例输入 Sample Input yeshowmuchiloveyoumydearmotherreallyicannotbeliev

最长公共子串

(连续) - 阿里笔试[分析+编码] 题目描述:给定一个query和一个text,均由小写字母组成.要求在text中找出以同样的顺序连续出现在query中的最长连续字母序列的长度.例如,query为“acbac”,text为“acaccbabb”,那么text中的“cba”为最长的连续出现在query中的字母序列,因此,返回结果应该为其长度3.请注意程序效率. [思路]用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0.然后求出对角线最长的1序列,其对应的位置

一天一道算法题(5)---最长公共子串

题目 给定两个字符串str1和str2,返回两个字符串的最长公共子串.例如:str1="1AB2345CD",str2="12345EF",公共子串是"2345" 解析 最长公共子串和最长公共子序列的区别是,子串是连续的,子序列是不连续的. 首先还是要生成动态规划表.生成大小为M*N的矩阵dp.dp[i][j]的含义是,在必须把str1[i]和str2[j]当作公共子串最后一个字符的情况下,公共子串最长能有多长.比如,str1="A12

[URAL-1517][求两个字符串的最长公共子串]

Freedom of Choice URAL - 1517 Background Before Albanian people could bear with the freedom of speech (this story is fully described in the problem "Freedom of speech"), another freedom - the freedom of choice - came down on them. In the near fu

POJ 2774 最长公共子串

对于最长公共子串,n*m的递推显然无法通过本题. 本题是后缀数组的一个基础应用,字符串的子串可以视作后缀的前缀. 我们在两个串间插入一个不在字符集的字符如'#'作为连接,这样做的目的是为了防止两个后缀的最长公共前缀跨过第一个字符串的末尾. 扫描Height数组,如果排名为i的字符串与排名为i-1的字符串来源于原来的2个串,则更新答案最大值. 1 #include <iostream> 2 #include <vector> 3 #include <algorithm>

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍. 这题的思路是这样的: 1)取较短的串的长度作为high,然后二分答案(每次判断长度为mid=(low+high)>>1是否存在,如果存在就增加下界:不存在就缩小上界): 2)主要是对答案的判断(judge函数