题目大意
给定若干个模板串
{Ti}
。你要求出一个最长的字符串
S
,使得
所有字符都是小写拉丁字母。
题目分析
建出模板串集合的
Trie
,然后在上面建个
SAM
。然后在
SAM
的所有长度大于等于
K
的点组成的集合中求最长路即可。注意
时间复杂度
O(∑|Ti|)
。
代码实现
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int INF=2000000000;
const int N=100050;
const int C=26;
const int S=N<<1;
int n,K,ans;
namespace SAM
{
struct node
{
int prt,len,size;
int nxt[C];
}sam[S];
int deg[S],f[S];
bool able[S];
queue<int> q;
int root,tot;
int newnode()
{
for (int c=0;c<C;c++) sam[tot].nxt[c]=0;
return sam[tot].prt=sam[tot].len=sam[tot].size=0,tot++;
}
void init(){tot=1,root=newnode();}
int insert(int c,int lst,int siz)
{
int p=lst,np=newnode(),q;
for (sam[np].len=sam[p].len+1,sam[np].size=siz;p&&!sam[p].nxt[c];p=sam[p].prt) sam[p].nxt[c]=np;
if (!p) sam[np].prt=root;
else if (sam[q=sam[p].nxt[c]].len==sam[p].len+1) sam[np].prt=q;
else
{
int nq=newnode();
sam[nq]=sam[q],sam[nq].size=0;
sam[np].prt=sam[q].prt=nq;
for (sam[nq].len=sam[p].len+1;p&&sam[p].nxt[c]==q;p=sam[p].prt) sam[p].nxt[c]=nq;
}
return np;
}
void calc()
{
memset(f,0,sizeof f),memset(deg,0,sizeof deg),memset(able,0,sizeof able);
for (int x=1;x<tot;x++) able[x]=sam[x].len>=K;
for (int x=1,y;x<tot;x++)
if (able[x])
for (int c=0;c<C;c++)
if ((y=sam[x].nxt[c])&&able[y]) ++deg[y];
else
{
int p=sam[x].prt;
for (;p&&!sam[p].nxt[c]&&sam[p].len+1>=K;p=sam[p].prt);
if (p&&sam[p].nxt[c]&&sam[p].len+1>=K) ++deg[sam[x].nxt[c]=sam[p].nxt[c]];
}
int ap=0;
for (int x=1;x<tot;x++)
{
ap+=able[x];
if (able[x]&&!deg[x]) q.push(x),f[x]=sam[x].len;
}
if (!ap)
{
ans=K-1;
return;
}
if (q.empty()) ans=INF;
else
{
for (int x,y;!q.empty();)
{
x=q.front(),q.pop();
for (int c=0;c<C;c++)
if (y=sam[x].nxt[c])
{
f[y]=max(f[y],f[x]+1);
if (!--deg[y]) q.push(y);
}
}
for (int x=1;x<tot;x++)
if (able[x]&°[x])
{
ans=INF;
return;
}
ans=0;
for (int x=1;x<tot;x++) if (able[x]) ans=max(ans,f[x]);
}
}
};
char s[N];
struct trie
{
int size[S],fa[S],node[S];
int nxt[S][C];
int root,tot;
queue<int> q;
int newnode()
{
for (int c=0;c<C;c++) nxt[tot][c]=0;
return fa[tot]=size[tot]=node[tot]=0,tot++;
}
void init(){tot=0,root=newnode();}
void insert()
{
int l=strlen(s),x=root;
for (int i=0;i<l;i++)
{
if (!nxt[x][s[i]-'a']) fa[nxt[x][s[i]-'a']=newnode()]=x;
++size[x=nxt[x][s[i]-'a']];
}
}
void build()
{
SAM::init(),node[root]=SAM::root,q.push(root);
for (int x;!q.empty();)
{
x=q.front(),q.pop();
for (int c=0,y;c<C;c++) if (y=nxt[x][c]) node[y]=SAM::insert(c,node[x],size[y]),q.push(y);
}
}
}t;
int main()
{
freopen("rhyme.in","r",stdin),freopen("rhyme.out","w",stdout);
for (;scanf("%d%d",&n,&K)!=EOF;)
{
t.init();
for (int i=1;i<=n;i++) scanf("%s",s),t.insert();
t.build(),SAM::calc();
if (ans==INF) printf("INF\n");
else printf("%d\n",ans);
}
fclose(stdin),fclose(stdout);
return 0;
}