UVA - 11107 Life Forms (广义后缀自动机)

题意:给你n个字符串,求出在超过一半的字符串中出现的所有子串中最长的子串,按字典序输出。

对这n个字符串建广义后缀自动机,建完后每个字符串在自动机上跑一遍,沿fail树向上更新所有子串结点的出现次数(指在n个字符串中的多少个串中出现,用siz表示),用vis数组判重,最后dfs输出结果就好了。

【后记】这个代码似乎有bug,被我自己给hack了...建议暴力对字典序排序

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int N=1000+10;
 5 int n,m,ka;
 6 char s[110][N],ss[N];
 7 int idx(char ch) {return ch-'a';}
 8 
 9 struct SAM {
10     static const int N=2e5+10,M=27;
11     int go[N][M],pre[N],len[N],tot,last,siz[N],vis[N],mx;
12     void init() {last=tot=0; newnode(0); pre[0]=-1;}
13     int newnode(int l) {
14         int u=tot++;
15         memset(go[u],0,sizeof go[u]);
16         len[u]=l,siz[u]=0;
17         return u;
18     }
19     void extend(int ch) {
20         int p=last,np=last=newnode(len[p]+1);
21         for(; ~p&&!go[p][ch]; p=pre[p])go[p][ch]=np;
22         if(!~p)pre[np]=0;
23         else {
24             int q=go[p][ch];
25             if(len[q]==len[p]+1)pre[np]=q;
26             else {
27                 int nq=newnode(len[p]+1);
28                 memcpy(go[nq],go[q],sizeof go[nq]);
29                 pre[nq]=pre[q],pre[q]=pre[np]=nq;
30                 for(; ~p&&go[p][ch]==q; p=pre[p])go[p][ch]=nq;
31             }
32         }
33     }
34     void dfs(int u,int dep) {
35         if(vis[u])return;
36         vis[u]=1;
37         if(siz[u]>m/2&&len[u]==mx)ss[dep]='\0',puts(ss);
38         for(int i=0; i<M; ++i)if(go[u][i])ss[dep]=i+'a',dfs(go[u][i],dep+1);
39     }
40     void run() {
41         memset(vis,-1,sizeof vis);
42         for(int t=0; t<m; ++t)
43             for(int i=0,u=0; s[t][i]; u=go[u][idx(s[t][i])],++i)
44                 for(int v=go[u][idx(s[t][i])]; v&&vis[v]!=t; v=pre[v])vis[v]=t,siz[v]++;
45         mx=-1;
46         for(int i=1; i<tot; ++i)if(siz[i]>m/2)mx=max(mx,len[i]);
47         memset(vis,0,sizeof vis);
48         if(mx==-1)puts("?");
49         else dfs(0,0);
50     }
51 } sam;
52 
53 int main() {
54     while(scanf("%d",&m)&&m) {
55         ka?puts(""):ka++;
56         sam.init();
57         for(int t=0; t<m; ++t) {
58             sam.last=0;
59             scanf("%s",s[t]);
60             n=strlen(s[t]);
61             for(int i=0; i<n; ++i)sam.extend(idx(s[t][i]));
62         }
63         sam.run();
64     }
65     return 0;
66 }

 

转载于:https://www.cnblogs.com/asdfsag/p/10339819.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值