【bzoj2946】[Poi2000]公共串 后缀自动机

来源:互联网 发布:vision软件怎么画图 编辑:程序博客网 时间:2024/05/17 10:52

Description

   给出几个由小写字母构成的单词,求它们最长的公共子串的长度。

任务:
l 读入单词
l 计算最长公共子串的长度
l 输出结果

Input

文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

Output

仅一行,一个整数,最长公共子串的长度。

Sample Input

3abcbbcaacbc

Sample Output

HINT

Source

.


把第一个串建后缀自动机

然后拿其它串在上面跑,记录每个串匹配到这个点的最大长度,然后在parent树上保存子树最小值(还有和val取min),然后对于所有串取最大值…

说的简单,代码…

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int SZ = 100010;const int INF = 1000000010;struct sam_node{    sam_node *ch[30],*par;    int val,ans[5];}T[SZ], *root, *last;int Tcnt = 0;sam_node* newnode(int x){    sam_node *k = T + (Tcnt ++);    k -> val = x;    memset(k -> ch,0,sizeof(k -> ch));    k -> par = 0;    memset(k -> ans,0,sizeof(k -> ans));    return k;}void insert(int x){    sam_node *p = last,*np = newnode(last -> val + 1);    while(p && !p -> ch[x])        p -> ch[x] = np,p = p -> par;    if(!p)        np -> par = root;    else    {        sam_node *q = p -> ch[x];        if(q -> val == p -> val + 1)            np -> par = q;        else        {            sam_node *nq = newnode(p -> val + 1);            memcpy(nq -> ch,q -> ch,sizeof(nq -> ch));            nq -> par = q -> par;            q -> par = np -> par = nq;            while(p && p -> ch[x] == q)                p -> ch[x] = nq,p = p -> par;        }    }    last = np;}void find(char s[],int id){    int l = strlen(s);    sam_node *p = root;    for(int i = 0,len = 0;i < l;i ++)    {        int c = s[i] - 'a' + 1;        if(p -> ch[c])        {            len ++;            p = p -> ch[c];        }        else        {            while(p != root && !p -> ch[c])                p = p -> par;            len = p -> val;            if(p -> ch[c])                p = p -> ch[c],len ++;        }        p -> ans[id] = max(p -> ans[id],min(p -> val,len));     }    for(int i = Tcnt - 1;i >= 1;i --)    {        sam_node *k = T + i;        k -> par -> ans[id] = min(k -> par -> val,max(k -> par -> ans[id],k -> ans[id]));    }}void init(){    root = newnode(0);    last = root;}int n;int dfs(sam_node *p){    int ans = INF;    for(int i = 1;i < n;i ++)        ans = min(ans,p -> ans[i]);    for(int i = 1;i <= 26;i ++)        if(p -> ch[i])            ans = max(ans,dfs(p -> ch[i]));    return ans;}char s[SZ];int main(){    init();    scanf("%d",&n);    scanf("%s",s);    int l = strlen(s);    for(int i = 0;i < l;i ++)        insert(s[i] - 'a' + 1);    for(int i = 1;i < n;i ++)    {        scanf("%s",s);        find(s,i);    }    printf("%d",dfs(root));    return 0;}/*3abdabdababd*/
0 0