[POJ2774]Long Long Message [CodeVS3160]最长公共子串 做题笔记

9 篇文章 0 订阅
7 篇文章 0 订阅

这两题其实是一题,代码可以在两边交
题目来源:http://codevs.cn/problem/3160/
http://poj.org/problem?id=2774

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

读入两个字符串

输出描述 Output Description
输出最长公共子串的长度
样例输入 Sample Input
yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
样例输出 Sample Output
27

数据范围及提示 Data Size & Hint
单个字符串的长度不超过100000

这题是后缀数组模板题。
一直在纠结到底是看SAM还是Suffix Array?
构造代码来自罗穗骞《后缀数组——处理字符串的有力工具》
构造代码一直看不懂QAQ,那就按ydc教主说的背下模板吧。主要应用是针对三个数组的。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=200010;
int r[maxn];
char a[maxn],b[maxn];
int lena,lenb,n;
int sa[maxn],rank[maxn],height[maxn];
int wa[maxn],ws[maxn],wv[maxn],wb[maxn];
bool cmp (int *r,int a,int b,int l) {
    return r[a]==r[b] && r[a+l]==r[b+l];
}
void da (int *r,int *sa,int n,int m) {
    int *x=wa, *y=wb;
    memset(ws,0,sizeof(ws));
    for (int i=0;i<n;i++) ws[x[i]=r[i]]++;
    for (int i=1;i<m;i++) ws[i]+=ws[i-1];
    for (int i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
    int p=1;
    for (int j=1;p<n;j<<=1,m=p) {
        p=0;
        for (int i=n-j;i<n;i++) y[p++]=i;
        for (int i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
        memset(ws,0,sizeof(ws));
        for (int i=0;i<n;i++) ws[wv[i]=x[y[i]]]++;
        for (int i=1;i<m;i++) ws[i]+=ws[i-1];
        for (int i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
        swap(x,y); x[sa[0]]=0; p=1;
        for (int i=1;i<n;i++) 
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}
void callheight (int *r,int *sa,int n) {
    for (int i=1;i<=n;i++) rank[sa[i]]=i;
    for (int i=0,k=0;i<n;height[rank[i++]]=k) {
        k?k--:0;
        for (int j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
    }
}
bool diff (int a,int b) {
    return (sa[a]<lena) ^ (sa[b]<lena);
}
int ans=0;
int main () {
    scanf("%s",a);scanf("%s",b);
    lena=strlen(a); lenb=strlen(b);
    n=lena+lenb+1;
    for (int i=0;i<lena;i++) r[i]=a[i];
    r[lena]='0';
    for (int i=0;i<lenb;i++) r[i+lena+1]=b[i];
    da(r,sa,n+1,128);
    callheight(r,sa,n);
    for (int i=3;i<=n;i++) 
        if (diff(i,i-1) && (height[i]>ans)) ans=height[i];
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值