题目大意
由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部。无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子。为了让自己的曲子更好听,小Z找到了一些好听曲子作为模板。曲谱可以表示成只包含小写字母的字符串,小Z希望自己最终的曲谱中任意一个长度为K的子串都是一个模板的子串。现在小Z想知道自己的曲谱最长可以是多长,如果可以无限长的话请输出INF。
解题思路
将k-1的串哈希,枚举一个串去掉头枚举一个尾看是否在哈希内,是就连一条有向边。跑拓扑排序有环即inf,否则跑最长路。
code
using namespace std;
int const maxl=1e5,mo=1e6+7;LL moo=1e9+7
int n,m,K,gra,to[maxl*26+10],next[maxl*26+10],begin[mo+10],dis[mo+10],
qu[mo+10],inq[mo+10],pre[mo+10],len,b[maxl+10];
char s[maxl+10];
ULL a[maxl+10],h[mo+10];
void insert(int u,int v){
to[++gra]=v+1;pre[v+1]++;
next[gra]=begin[u+1];
begin[u+1]=gra;
}
int hash(ULL x){
int y=x%mo;
while(h[y]&&(h[y]!=x))y=y%mo+1;
return y;
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);int ha,cnt=0;
while(scanf("%d%d\n",&n,&K)!=EOF){
gra=0;fo(i,1,mo)begin[i]=pre[i]=h[i]=0;if(K==2)K++;
ULL bit=1;fo(i,1,K-2)bit=bit*26;cnt=0;
int ans=0;
fo(cas,0,n-1){
scanf("%s\n",&s[1]);len=strlen(&s[1]);
if((len<K)&&(!((len==2))))continue;
a[++cnt]=0;
fo(i,1,K-1)a[cnt]=a[cnt]*26+s[i]-'a';ha=hash(a[cnt]),h[ha]=a[cnt],b[cnt]=s[1]-'a';
fo(i,K,len)ha=hash(a[cnt+1]=(a[cnt]-(s[i-K+1]-'a')*bit)*26+s[i]-'a'),h[ha]=a[++cnt],b[cnt]=s[i-K+2]-'a';
if(K<=len)cnt--;
}
fo(i,1,cnt)fo(j,0,25){
ha=hash((a[i]-b[i]*bit)*26+j);
if(h[ha])insert(hash(a[i]),ha);
}
int he=0,ti=0;
fo(i,1,mo){
dis[i]=K-1;
if(!pre[i])inq[qu[++ti]=i]=1;
}
while(he!=ti){
int now=qu[++he];
for(int i=begin[now];i;i=next[i]){
dis[to[i]]=max(dis[to[i]],dis[now]+1);
if(!(--pre[to[i]]))inq[qu[++ti]=to[i]]=1;
}
}
fo(i,1,mo)ans=max(ans,dis[i]);
if((ti!=mo)||(K==1))printf("INF\n");
else printf("%d\n",ans);
}
return 0;
}