(写的都是初中小朋友czl早就切过的题……)
http://www.cnblogs.com/Lyush/p/3281546.html
POJ-1509 Glass Beads
UVA - 719 Glass Beads
题意:一个字符串可以将第一个字符放到最后一位,然后问不断这样做可以得到的字典序最小的字符串
sam模板题,copy一遍建个sam,然后直接在sam中跑一遍就行了。
sam记录了字符串的所有后缀(也随便记录了字串),从root开始到每个接受态节点都是一个后缀(或多个),从root开始到每个节点都是一个子串(或多个)。由于copy一遍后把所有的情况的包括进去了,那么只要跑len(原长)遍就行了!
const maxn=30000; var step,pre:array[0..maxn]of longint; son:array[0..maxn,0..25]of longint; tot,tail,t:longint; procedure add(x:longint); var i,j,k,np,p:longint; begin p:=tail; inc(tot); np:=tot; step[np]:=step[tail]+1; while (p>=0) and (son[p,x]=-1) do begin son[p,x]:=np; p:=pre[p]; end; tail:=np; if p<0 then pre[np]:=0 else if step[son[p,x]]=step[p]+1 then pre[np]:=son[p,x] else begin j:=son[p,x]; inc(tot); k:=tot; for i:=0 to 25 do son[k,i]:=son[j,i]; step[k]:=step[p]+1; pre[k]:=pre[j]; pre[j]:=k; pre[np]:=k; while (p>=0) and (son[p,x]=j) do begin son[p,x]:=k; p:=pre[p]; end; end; end; procedure work; var s:ansistring; len,i,j,k,p:longint; begin readln(s); len:=length(s); s:=s+s; for i:=1 to len<<1 do add(ord(s[i])-97); p:=0; for i:=1 to len do for j:=0 to 25 do if son[p,j]>=0 then begin p:=son[p,j]; break; end; writeln(step[p]-len+1); end; begin readln(t); while t>0 do begin dec(t); fillchar(pre,sizeof(pre),255); fillchar(son,sizeof(son),255); fillchar(step,sizeof(step),0); tot:=0; tail:=0; work; end end.