【后缀自动机】SPOJ 1811-LCS

题意

  给你两个字符串,求他们的LCS的长度 N <= 2.5e5 时限0.25s左右

 

后缀自动机练习...不知道hash行不行我想去试一发。

 

本题要用到的是后缀自动机的一个性质:

  构建自动机时用到的step数组,之前以为是没什么用的,原来还能这样,长知识了。

  step[i]表示的是【从root节点走到i这个节点,经过了几个字符】,这个性质在匹配时失配的情况下可以用来更新当前答案。

 

  利用第一个字符串建立一个SAM,然后用第二个字符串来在自动机上进行匹配,看看最长能匹配多远就是答案了。

 

在失配的时候考虑两种情况:

  1,因为now的pre链上的点与now点具有相同的后缀,因此如果都已经匹配到now点了,那么now.pre肯定已经出现过了,因此可以跳到pre上重新匹配。

  2,如果一直跳到了0,即整条pre链上都没有当前的字符,所以长度清空,继续匹配。

 

注意的是每次匹配完之后ans都要对当前的len取一个max。

 

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <iostream>
 5 #define maxn 255000*2
 6 using namespace std;
 7 
 8 struct node { int s[26],pre; } Suf[maxn];
 9 char S[maxn],T[maxn];
10 int i,j,n,m,k,len1,len2,len,last = 1,root = 1,cnt = 1,ans;
11 int step[maxn];
12 
13 void add(int nxt)
14 {
15     int now = ++cnt, p = last;
16     step[now] = step[p] + 1;
17     for ( ; p != 0 && Suf[p].s[nxt] == 0; p = Suf[p].pre) Suf[p].s[nxt] = now;
18     if (p == 0) Suf[now].pre = root;
19     else
20     {
21         int q = Suf[p].s[nxt];
22         if (step[q] == step[p] + 1) Suf[now].pre = q;
23         else
24         {
25             int nq = ++cnt;
26             step[nq] = step[p] + 1;
27             Suf[nq] = Suf[q];
28             Suf[q].pre = Suf[now].pre = nq;
29             for ( ; p != 0 && Suf[p].s[nxt] == q; p = Suf[p].pre) Suf[p].s[nxt] = nq;
30         }
31     }
32     last = now;
33 }
34             
35 int main()
36 {
37     while ( scanf("%s\n%s\n",S+1,T+1) != EOF )
38     {    
39         memset(Suf,0,sizeof(Suf)); memset(step,0,sizeof(step)); cnt = 1; last = 1; ans = 0;
40         len1 = strlen(S+1); len2 = strlen(T+1);
41     
42         for (i = 1; i <= len1; i++) add(S[i]-'a');
43     
44             int now = root,len = 0;
45         for (i = 1; i <= len2; i++)
46         {
47             int nxt = T[i]-'a';
48             if (Suf[now].s[nxt] != 0) 
49                     {
50                 len++;
51                 now = Suf[now].s[nxt];
52             }
53             else
54             {
55                 while (Suf[now].s[nxt] == 0 && now != 0) now = Suf[now].pre;
56                 if (now == 0) now = root,len = 0;
57                 else len = step[now] + 1,now = Suf[now].s[nxt];
58             }
59             ans = max(ans,len);
60         }
61     
62         printf("%d\n",ans);
63     }
64     return 0;
65 }
SPOJ 1811

 

posted on 2015-01-09 21:31  MMMoonLighttt  阅读(569)  评论(1编辑  收藏  举报

导航