最长公共子串2(LCS2) lg SP1812
题意:n个字符串(n<=10)求最长公共子串的长度
前置技能点:https://www.cnblogs.com/wenci/p/10432932.html (两个字符串求最长公共子串的长度)
既然知道了两个串的最长公共子串怎么求
那我们延伸一下,考虑两个变量,maxx表示在当前拿上来匹配得这个串在每个节点为终点时最长匹配的长度
minn表示在之前所有串上匹配完,到当前节点最长匹配的长度
先解释一下拓扑序的基数排序
inline void radix_sort(){ int i,j,k; for(i=1;i<=tot;i++){ tong[node[i].len]++; }//开桶记录长度 for(i=1;i<=tot;i++){ tong[i]+=tong[i-1]; }//表示当前长度能排到多少名 for(i=1;i<=tot;i++){ id[tong[node[i].len]--]=i;//重新排序后的数值 } }
每一个串重新匹配的操作
inline bool work(){ if(scanf("%s",s)==EOF) return false; int p=1,len=0;int i,j,k; for(i=1;i<=tot;i++){ node[i].maxx=0; }//把当前串的最大匹配清零 int l1=strlen(s); for(i=0;i<l1;i++){ int now=s[i]-'a'+1; if(node[p].ch[now]){ p=node[p].ch[now];len++; } else{ while(p&&!node[p].ch[now]){ p=node[p].fa; } if(!p){ p=1;len=0; } else{ len=node[p].len+1;p=node[p].ch[now]; } }//以上都和两个串匹配操作一样 node[p].maxx=max(node[p].maxx,len);//这里更新一下当前串的最大匹配 } for(i=tot;i;i--){//按照倒拓扑序,要优先修改儿子节点更新父亲节点 int t=id[i];//基数排序后的序号 node[t].minn=min(node[t].minn,node[t].maxx);//更新当前节点的最大匹配 if(node[t].maxx>=node[t].len&&node[t].fa){//如果当前节点是满匹配的,那么删去结尾最后一个,也是满匹配的 node[node[t].fa].maxx=node[node[t].fa].len;//把父亲节点的匹配也更新了 } } return true; }
最后贴整篇代码
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f inline int read(){ int w=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ w=(w<<3)+(w<<1)+ch-48; ch=getchar(); } return w*f; } int n,m,lst=1,tot=1; long long size[2000010],sum[2000010]; struct Node{ int ch[30],len,fa,maxx,minn; }node[2000010]; bool flag; inline void extend(int now){ int p=lst;tot++;lst=tot;int np=tot; node[np].len=node[p].len+1; while(p&&!node[p].ch[now]){ node[p].ch[now]=np; p=node[p].fa; } if(!p) node[np].fa = 1; else{ int q = node[p].ch[now]; if(node[q].len == node[p].len + 1){ node[np].fa = q; } else{ int nq=++tot;node[nq]=node[q]; node[nq].len=node[p].len+1; node[np].fa=node[q].fa=nq; while(p&&node[p].ch[now] == q){ node[p].ch[now]=nq; p=node[p].fa; } } } } int tong[2000010],id[2000010],ans; char s[2000010]; inline void radix_sort(){ int i,j,k; for(i=1;i<=tot;i++){ tong[node[i].len]++; } for(i=1;i<=tot;i++){ tong[i]+=tong[i-1]; } for(i=1;i<=tot;i++){ id[tong[node[i].len]--]=i; } } inline bool work(){ if(scanf("%s",s)==EOF) return false; int p=1,len=0;int i,j,k; for(i=1;i<=tot;i++){ node[i].maxx=0; } int l1=strlen(s); for(i=0;i<l1;i++){ int now=s[i]-'a'+1; if(node[p].ch[now]){ p=node[p].ch[now];len++; } else{ while(p&&!node[p].ch[now]){ p=node[p].fa; } if(!p){ p=1;len=0; } else{ len=node[p].len+1;p=node[p].ch[now]; } } node[p].maxx=max(node[p].maxx,len); } for(i=tot;i;i--){ int t=id[i]; node[t].minn=min(node[t].minn,node[t].maxx); if(node[t].maxx>=node[t].len&&node[t].fa){ node[node[t].fa].maxx=node[node[t].fa].len; } } return true; } int main(){ scanf("%s",s);int i,j,k; int l=strlen(s); for(i=0;i<=l;i++){ extend(s[i]-'a'+1); } radix_sort(); for(i=1;i<=tot;i++){ node[i].minn=node[i].len; } while(work()); for(i=1;i<=tot;i++){ ans=max(ans,node[i].minn); } cout<<ans<<endl; return 0; }