首页 > 代码库 > 【后缀自动机】SPOJ 1812-LCSII

【后缀自动机】SPOJ 1812-LCSII

题意:

  给出最多10个长度不超过100000的字符串,求他们的LCS的长度。时限是鬼畜的0.25s 。

 

后缀自动机练习...技术分享虽然有人这么说但我并不觉得hash能过。

 

本题可以说是【论SAM中按step排序更新pre的重要性】:

  总的来说做法和1811-LCS有点类似,不同的是因为有多个字符串,因此每个字符串都需要在SAM上跑一次。

  记录下每个节点最长能容纳长度为多少的字符,最后取个MAX就行了。

 

  用nans[i]表示匹配当前字符串时,i号点能容纳的子串长度,如果i的pre上的当前答案比i还要小的话就用nans[i]来更新nans[i.pre] 。

  用ans表示所有nans的最小值,在计算每个字符串时用nans来更新ans,最后在ans中找一个MAX就可以了。

 

一开始忘记了黑体的那句话,结果拍了很久又没拍出来,提交的时候在第10个点WA了简直难过...

 

技术分享
 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 #define maxn 105000*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;11 int step[maxn],nans[maxn],ans[maxn],f[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     else20     {21         int q = Suf[p].s[nxt];22         if (step[q] == step[p] + 1) Suf[now].pre = q;23         else24         {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 bool cmp(int a,int b) { return step[a] < step[b]; }36 37 int main()38 {39     scanf("%s\n",S+1);40     len1 = strlen(S+1);41     for (i = 1; i <= len1; i++) add(S[i]-a);42     43     for (i = 1; i <= cnt; i++) f[i] = i;44     stable_sort(f+1,f+1+cnt,cmp);45 46     memcpy(ans,step,sizeof(ans));47     48     while (scanf("%s\n",T+1) != EOF)49     {50         memset(nans,0,sizeof(nans));51         52         len2 = strlen(T+1);53         int now = root,len = 0;54         for (i = 1; i <= len2; i++)55         {56             int nxt = T[i]-a;57             if (Suf[now].s[nxt] != 0) 58             {59                 len++;60                 now = Suf[now].s[nxt];61                 nans[now] = max(nans[now],len);62             }63             else64             {65                 while (Suf[now].s[nxt] == 0 && now != 0) now = Suf[now].pre;66                 if (now == 0) now = root,len = 0;67                 else len = step[now] + 1,now = Suf[now].s[nxt],nans[now] = max(nans[now],len);68             }69         }70         for (i = cnt; i >= 1; i--)71         {72             ans[f[i]] = min(ans[f[i]],nans[f[i]]);73             nans[Suf[f[i]].pre] = max(nans[Suf[f[i]].pre],nans[f[i]]);74         }75     }76     77     int ANS = 0;78     for (i = 1; i <= cnt; i++)79         ANS = max(ANS,ans[i]);80     81     printf("%d\n",ANS);82     return 0;83 }
SPOJ 1812

 

【后缀自动机】SPOJ 1812-LCSII