刷题总结——spoj1812(后缀自动机+DP)

题目:

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 simple, for two 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 exactly two lines, each line consists of no more than 250000 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

Output:
3

Notice: new testcases added

 Submit solution!

题解:

注:参照神犇hahalidaxin的题解.

SAM+DP

先拿个串建个SAM,然后用后面的串匹配,每次将所有的匹配长度记录在状态上取min,然后对所有状态取max即答案。

需要更新fa,因为fa[p]一定比p更优,但匹配的时候可能只更新了p而没有更新fa[p],所以还需要递推一边。

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

心得:

目前没什么好说的··dp和sam都不熟的情况下想做这道题真的很懵b····感觉没什么收获··以后再来看看吧···

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=250005;
int pre[N],son[N][26],step[N],last=1,root=1,tot=1,minn[N],maxx[N];
int cnt[N],len,b[N];
char s[N];
struct suffix_auto
{
  void extend(int ch)
  {
    int p=last,np=++tot;
    minn[tot]=step[tot]=step[last]+1;
    for(;p&&!son[p][ch];p=pre[p])  son[p][ch]=np;
    if(!p)  pre[np]=root;
    else
    {
      int q=son[p][ch];
      if(step[q]!=step[p]+1)
      {
        int nq=++tot;  
        minn[nq]=step[nq]=step[p]+1;
        memcpy(son[nq],son[q],sizeof(son[q]));
        pre[nq]=pre[q];
        pre[q]=pre[np]=nq;
        for(;son[p][ch]==q;p=pre[p])  son[p][ch]=nq;
      }
      else
        pre[np]=q;    
    }
    last=np;
  }
  void build()
  {
    scanf("%s",s);
    len=strlen(s);
    for(int i=0;i<len;i++)
      extend(s[i]-'a');
  }
}automa;
int main()
{
  freopen("a.in","r",stdin);
  automa.build();
  for(int i=1;i<=tot;i++)  cnt[step[i]]++;
  for(int i=1;i<=len;i++)  cnt[i]+=cnt[i-1];
  for(int i=1;i<=tot;i++)  b[cnt[step[i]]--]=i;
  while(scanf("%s",s)==1)
  {
    int len1=strlen(s);  
    int p=root,len=0;
    for(int i=0;i<len1;i++)
    {
      int ch=s[i]-'a';
      if(son[p][ch])  len++,p=son[p][ch];
      else
      {
        while(p&&!son[p][ch])  p=pre[p];
        if(!p)  len=0,p=root;
        else
        {
          len=step[p]+1;
          p=son[p][ch];
        }
      }
      if(maxx[p]<len)  maxx[p]=len;
    }
    for(int i=tot;i;i--)  
    { 
      int j=b[i];
      if(maxx[j]<minn[j])  minn[j]=maxx[j];
      if(pre[p]&&maxx[pre[j]]<maxx[j])  maxx[pre[j]]=maxx[j];
      maxx[j]=0;
    }
  }
  int ans=0;
  for(int i=1;i<=tot;i++)
    ans=max(ans,minn[i]);
  cout<<ans<<endl;
  return 0;
}

 

 

 

 

 

  

posted @ 2017-03-24 17:05  AseanA  阅读(275)  评论(0编辑  收藏  举报