SPOJ LCS2 Longest Common Substring II + BZOJ 2946 [Poi2000]公共串

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

Notice:

new testcases added

思路

BZOJ是权限题,不放题目描述了;
其实这两道题是双倍经验题;
对第一个串建SAM,把后面的串放在这个SAM上跑,记录到达一个节点这一个串的最长的长度,到达一个点需要把它的parent树上的祖先全部更新一遍,对每个记录所有串的最小值,这些节点记录的值的最大值就是答案。

ans=max(节点的答案=min(串到达这个节点的最长长度=max(串到达这个节点的长度)))

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

const int maxn=250000;
const int maxk=500000;

struct node
{
  node* tr[26];
  node* par;
  int maxl,num;
};

struct suffix_automaton
{
  node* qs;
  node* qlast;
  node samnode[maxk+10];
  int cnt,tmp[maxk+10],ans[maxk+10],ki[maxk+10];

  inline int clear()
  {
    delete qs;
    delete qlast;
    qlast=qs=new node();
    cnt=0;
    return 0;
  }

  inline int addchr(int ch)
  {
    node* p=qlast;
    node* np=&samnode[++cnt];
    np->maxl=qlast->maxl+1;
    qlast=np;
    np->num=cnt;
    while((p!=NULL)&&(p->tr[ch]==NULL))
      {
        p->tr[ch]=np;
        p=p->par;
      }
    if(p==NULL)
      {
        np->par=qs;
        return 0;
      }
    node* q=p->tr[ch];
    if(q->maxl!=p->maxl+1)
      {
        node* nq=&samnode[++cnt];
        nq->maxl=p->maxl+1;
        nq->num=cnt;
        memcpy(nq->tr,q->tr,sizeof q->tr);
        nq->par=q->par;
        q->par=np->par=nq;
        while((p!=NULL)&&(p->tr[ch]==q))
          {
            p->tr[ch]=nq;
            p=p->par;
          }
      }
    else
      {
        np->par=q;
      }
    return 0;
  }

  inline int sortmaxl()
  {
    for(register int i=1; i<=cnt; ++i)
      {
        ans[i]=samnode[i].maxl;
      }
    for(register int i=1; i<=cnt; ++i)
      {
        ++tmp[samnode[i].maxl];
      }
    for(register int i=2; i<=cnt; ++i)
      {
        tmp[i]+=tmp[i-1];
      }
    for(register int i=cnt; i; --i)
      {
        ki[tmp[samnode[i].maxl]--]=i;
      }
    return 0;
  }

  inline int run(char* s,int len)
  {
    node* q=qs;
    int l=0;
    memset(tmp,0,sizeof tmp);
    for(register int i=1; i<=len; ++i)
      {
        int ch=s[i]-'a';
        while((q!=NULL)&&(q->tr[ch]==NULL))
          {
            q=q->par;
          }
        if(q==NULL)
          {
            q=qs;
            l=0;
          }
        else
          {
            l=std::min(l,q->maxl)+1;
            q=q->tr[ch];
          }
        tmp[q->num]=std::max(tmp[q->num],l);
      }
    for(register int i=cnt; i; --i)
      {
        tmp[samnode[ki[i]].par->num]=std::max(tmp[samnode[ki[i]].par->num],tmp[ki[i]]);
      }
    for(register int i=1; i<=cnt; ++i)
      {
        ans[i]=std::min(ans[i],tmp[i]);
      }
    return 0;
  }

  inline int lcs()
  {
    int a=0;
    for(register int i=1; i<=cnt; ++i)
      {
        a=std::max(a,ans[i]);
      }
    return a;
  }
};

suffix_automaton sam;
char s[maxn+10];

int main()
{
  scanf("%s",s+1);
  int len=strlen(s+1);
  sam.clear();
  for(register int i=1; i<=len; ++i)
    {
      sam.addchr(s[i]-'a');
    }
  sam.sortmaxl();
  while(~scanf("%s",s+1))
    {
      sam.run(s,strlen(s+1));
    }
  printf("%d\n",sam.lcs());
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值