ZOJ2006 (后缀自动机)

求一个字符串的最小表示法。

将字符串S倍长,从根走length(s)步所走路径即为最小表示法。

记所到达位置为x,则这个最小表示法的起点为a[x]-len(s)+1

 1 const maxn=20008;
 2 var T:longint;
 3     nt:array[0..maxn,'a'..'z'] of longint;
 4     a,f:array[0..maxn] of longint;
 5     sum,last:longint;
 6     s:ansistring;
 7 procedure Sam_init;
 8 begin
 9     fillchar(nt,sizeof(nt),255);
10     fillchar(a,sizeof(a),0);
11     fillchar(f,sizeof(f),255);
12     sum:=0; last:=0;
13 end;
14 procedure Sam_ins(i:longint);
15 var p,q,np,nq:longint;
16     ch:char;
17 begin
18     ch:=s[i];
19     p:=last; inc(sum); np:=sum; a[np]:=a[p]+1; last:=np; 
20     while (p<>-1) and (nt[p][ch]=-1) do begin nt[p][ch]:=np; p:=f[p]; end;
21     if p=-1 then f[np]:=0 else
22     begin
23         q:=nt[p][ch];
24         if a[p]+1=a[q] then f[np]:=q else
25         begin
26             inc(sum); nq:=sum; a[nq]:=a[p]+1;
27             nt[nq]:=nt[q]; f[nq]:=f[q];
28             f[q]:=nq; f[np]:=nq;
29             while (p<>-1) and (nt[p][ch]=q) do begin nt[p][ch]:=nq; p:=f[p]; end;        
30         end;    
31     end;
32 end;
33 procedure dfs(now,len:longint);
34 var ch:char;
35 begin
36     if len=0 then
37     begin
38         writeln(a[now]-length(s) div 2+1);
39         exit;
40     end;
41     for ch:='a' to 'z' do
42         if nt[now][ch]<>-1 then
43         begin
44             dfs(nt[now][ch],len-1);
45             exit;
46         end;
47 end;
48 procedure main;
49 var i:longint;
50 begin
51     readln(s);
52     s:=s+s;
53     Sam_init;
54     for i:=1 to length(s) do Sam_ins(i);
55     dfs(0,length(s) div 2);
56 end;
57 begin
58     readln(T);
59     while T>0 do begin dec(T); main; end;
60 end.
原文地址:https://www.cnblogs.com/rpSebastian/p/4566381.html