题目
Description
由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部。无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子。为了让自己的曲子更好听,小Z找到了一些好听曲子作为模板。曲谱可以表示成只包含小写字母的字符串,小Z希望自己最终的曲谱中任意一个长度为K的子串都是一个模板的子串。现在小Z想知道自己的曲谱最长可以是多长,如果可以无限长的话请输出INF。
Input
本题的每个测试点有多组数据,对于每组数据:
第一行两个整数N,K分别表示模板的个数与K值。
接下来N行,每行一个字符串表示一个模板。(只包含’a’~’z’)
Output
对于每组数据输出一行表示曲子最长可以是多长,如果可以无限长的话输出INF。
Sample Input
1 4
abcabc
1 5
abcabc
Sample Output
INF
6
Data Constraint
对于30%的数据:K=2。
对于70%的数据:每组数据字符串总长不超过1000。
对于100%的数据:每组数据字符串总长不超过100000,1≤K≤100000。每个测试点数据不超过10组。
Hint
第一个样例的曲子可以是”abc”不断循环。
第二个样例的曲子最长是”abcabc”。
题解
一开始觉得这道题应该是SAM之类的高级算法题,然而后来发现是一道套路题
首先我们可以把每一个长度为K-1的字符串看成是一个节点,然后对于一个输入中的字符串,显然是可以从s[1..k-1]向S[2..K]连接一条有向边的,那么我们就得到了一个有向图
现在的问题就变成了
1:这个有向图是否有环
2:如果没有环,那么从一个节点出发,最多可以走多少个点
如果第一个问题成立那么答案显然是INF
对于第二个问题考虑做一次DAG
字符串转成数字可以用双hash
贴代码
const h1=103007; h2=21478647;
var
h:array[0..200005]of int64;
a,b:array[0..200005,1..2]of longint;
a1,dp,now,next:array[0..200005]of longint;
bz:array[0..200005]of boolean;
s:array[0..100005]of longint;
i,j,k,l,m,n,x,y,z,c1,c2,d1,d2,p,ans,e1,e2:longint;
ch:char;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;
function hash(c1,c2:longint):longint;
var
x:longint;
begin
x:=c1;
while (h[x]<>c2) and (h[x]<>0) do x:=(x+1) mod h1;
h[x]:=c2;
{while ((h[x,1]<>c1) or (h[x,2]<>c2)) do
begin
if (h[x,1]=0) and (h[x,2]=0) then
begin
h[x,1]:=c1;
h[x,2]:=c2;
break;
end;
x:=x mod h1+1;
end; }
exit(x);
end;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=a[(i+j) div 2,1];
repeat
while a[i,1]<mid do inc(i);
while a[j,1]>mid do dec(j);
if i<=j then
begin
a[0]:=a[i];
a[i]:=a[j];
a[j]:=a[0];
inc(i);
dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure star;
begin
b[a[1,1],1]:=1;
for i:=2 to z do
if a[i,1]<>a[i-1,1] then
begin
b[a[i-1,1],2]:=i-1;
b[a[i,1],1]:=i;
end;
b[a[z,1],2]:=z;
end;
procedure work;
begin
readln(n,m);
if n=0 then exit;
fillchar(dp,sizeof(dp),0);
fillchar(s,sizeof(s),0);
fillchar(h,sizeof(h),0);
fillchar(bz,sizeof(bz),false);
fillchar(a1,sizeof(a1),0);
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
z:=0;
for i:=1 to n do
begin
c1:=0;
c2:=0;
e1:=1;
e2:=1;
p:=0;
j:=1;
while not eoln do
begin
read(ch);
inc(p); s[p]:=ord(ch)-96;
inc(j);
if j=m then break;
end;
{if j<m-1 then
begin
readln;
writeln(m);
exit;
end; }
for j:=m-1 downto 1 do
begin
c1:=(c1+e1*s[j]) mod h1;
c2:=(c2+e2*s[j]) mod h2;
if j=1 then break;
e1:=(e1*26) mod h1;
e2:=(e2*26) mod h2;
end;
if (c1<0) or (c2<0) then
begin
c1:=c1;
end;
x:=hash(c1,c2);
//if ord(ch)-96<>c1 then writeln('!');
while not eoln do
begin
read(ch);
inc(p); s[p]:=ord(ch)-96;
c1:=(c1-(s[p-m+1]*e1) mod h1+h1) mod h1;
c1:=(c1*26+s[p]) mod h1;
c2:=(c2-(s[p-m+1]*e2) mod h2+h2) mod h2;
c2:=(c2*26+s[p]) mod h2;
y:=hash(c1,c2);
inc(z);
a[z,1]:=x;
a[z,2]:=y;
x:=y;
end;
//if ord(ch)-96<>c1 then writeln('!');
readln;
end;
if m=1 then
begin
writeln('INF');
exit;
end;
qsort(1,z);
star;
p:=0;
if n=10 then
begin
ans:=ans;
end;
for i:=1 to z do
begin
if bz[a[i,1]]=false then
begin
bz[a[i,1]]:=true;
inc(p);
end; // else writeln(chr(a[i,1]+96));
if bz[a[i,2]]=false then
begin
bz[a[i,2]]:=true;
inc(p);
end; //else writeln(chr(a[i,2]+96));
inc(a1[a[i,2]]);
end;
now[0]:=0;
for i:=1 to z do
if (a1[a[i,1]]=0) and (bz[a[i,1]]=true) then
begin
inc(now[0]);
now[now[0]]:=a[i,1];
bz[a[i,1]]:=false;
dec(p);
end;
ans:=0;
while p>0 do
begin
if now[0]=0 then
begin
writeln('INF');
break;
end;
next[0]:=0;
for i:=1 to now[0] do
begin
x:=now[i];
for j:=b[x,1] to b[x,2] do
if j<>0 then
begin
dec(a1[a[j,2]]);
if a1[a[j,2]]=0 then
begin
{if bz[a[j,2]]=false then
begin
ans:=ans;
end;
bz[a[j,2]]:=false;}
inc(next[0]);
next[next[0]]:=a[j,2];
dec(p);
end;
dp[a[j,2]]:=max(dp[a[j,2]],dp[a[j,1]]+1);
ans:=max(ans,dp[a[j,2]]);
end;
end;
for i:=0 to next[0] do now[i]:=next[i];
end;
if p=0 then writeln(ans+m-1);
end;
begin
//assign(input,'t2.in'); reset(input);
assign(input,'rhyme.in'); reset(input);
assign(output,'rhyme.out'); rewrite(output);
while not eof do work;
close(input); close(output);
end.