题意:给你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 }