【题意】
给定一个字符串(长度不超过100000),要求输出重复次数最多的字典序最小的子串
【输入】
多组数据,每组数据一行,为一个小写字母组成的字符串
数据以#结束
【输出】
每组输出'Case *: '+重复次数最多字典序最小的子串
后缀数组求解
然后枚举重复部分的长度l
然后在l+1、2*l+1...位置枚举
若枚举到l+1若1和l+1上的字符相同,
则求1和l+1向前匹配的长度和向后匹配的长度。
然后将向前向后匹配长度相加再加上l然后div l
便是重复次数p
字典序的比较,比较一下起点的rank即可
需要注意的是向前匹配的最左端到最右端向前p*l都可以作为字符串的起点
用st算法可求出rank最小的起点
program poj3693; const ln2=1/ln(2); type arr=array [-1..100001] of longint; arra=array [0..18,0..100001] of longint; var n,i,j,k,l,max,where,t,s,e,mid,long,q,p,tot:longint; ok:boolean; root,nroot:ansistring; nrank,nheight,sa,dl,height,total,rank,now,keep,change:arr; min,dict,nmin:arra; procedure swap (var a,b:longint); var i:longint; begin i:=a; a:=b; b:=i; end; procedure solve (var rank,height:arr;root:ansistring); begin fillchar(total,sizeof(total),0); for i:=1 to n do inc(total[ord(root[i])-96]); for i:=1 to 26 do total[i]:=total[i-1]+total[i]; for i:=1 to n do rank[i]:=total[ord(root[i])-97]+1; k:=0; while 1 shl k<n do begin for i:=1 to n do if i+(1 shl k)>n then change[i]:=0 else change[i]:=rank[i+(1 shl k)]; fillchar(total,sizeof(total),0); for i:=1 to n do inc(total[change[i]]); for i:=1 to n do total[i]:=total[i]+total[i-1]; for i:=1 to n do begin dl[total[change[i]-1]+1]:=i; inc(total[change[i]-1]); end; fillchar(total,sizeof(total),0); ok:=true; for i:=1 to n do begin inc(total[rank[i]]); if total[rank[i]]=2 then ok:=false; end; if ok then break; for i:=2 to n do total[i]:=total[i]+total[i-1]; fillchar(now,sizeof(now),0); fillchar(keep,sizeof(keep),0); for i:=1 to n do begin if now[rank[dl[i]]]<>change[dl[i]] then begin now[rank[dl[i]]]:=change[dl[i]]; total[rank[dl[i]]-1]:=total[rank[dl[i]]-1]+keep[rank[dl[i]]]; keep[rank[dl[i]]]:=0; end; inc(keep[rank[dl[i]]]); rank[dl[i]]:=total[rank[dl[i]]-1]+1; end; inc(k); end; for i:=1 to n do sa[rank[i]]:=i; fillchar(height,sizeof(height),0); for i:=1 to n do begin if rank[i]=1 then continue; k:=height[rank[i-1]]-1; if k<0 then k:=0; while (i+k<=n)and(sa[rank[i]-1]+k<=n)and(root[i+k]=root[sa[rank[i]-1]+k]) do inc(k); height[rank[i]]:=k; end; end; procedure st (var height:arr;var min:arra); begin for i:=1 to n do min[0,i]:=height[i]; k:=0; while 1 shl k<n do begin for i:=1 to n do if i+(1 shl k)>n then min[k+1,i]:=min[k,i] else if min[k,i]<min[k,i+(1 shl k)] then min[k+1,i]:=min[k,i] else min[k+1,i]:=min[k,i+(1 shl k)]; inc(k); end; end; procedure dictst; begin for i:=1 to n do dict[0,i]:=i; k:=0; while 1 shl k<n do begin for i:=1 to n do if i+(1 shl k)>n then dict[k+1,i]:=dict[k,i] else if rank[dict[k,i]]<rank[dict[k,i+(1 shl k)]] then dict[k+1,i]:=dict[k,i] else dict[k+1,i]:=dict[k,i+(1 shl k)]; inc(k); end; end; function similar (a,b:longint;var min:arra;var rank,height:arr):longint; var i:longint; begin if a=b then exit(n-a+1); a:=rank[a]; b:=rank[b]; if a>b then swap(a,b); inc(a); if a=b then exit(height[a]); i:=trunc(ln(b-a)*ln2); while (i>0)and(1 shl i>=b-a+1) do dec(i); if min[i,a]<min[i,b-(1 shl i)+1] then exit(min[i,a]) else exit(min[i,b-(1 shl i)+1]); end; function similardict (a,b:longint):longint; var i:longint; begin if a=b then exit(a); i:=trunc(ln(b-a)*ln2); while (i>0)and(1 shl i>=b-a+1) do dec(i); if rank[dict[i,a]]<rank[dict[i,b-(1 shl i)+1]] then exit(dict[i,a]) else exit(dict[i,b-(1 shl i)+1]); end; begin t:=0; repeat readln(root); if root='#' then break; inc(t); n:=length(root); tot:=0; solve(rank,height,root); st(height,min); nroot:=root; for i:=1 to n do nroot[i]:=root[n-i+1]; solve(nrank,nheight,nroot); st(nheight,nmin); dictst; max:=1; long:=1; where:=1; for i:=2 to n do if root[i]<root[where] then where:=i; for l:=1 to n div 2 do if n div l >= max then for i:=1 to n div l do if n div l - i + 3>=max then begin if i*l+1>n then continue; if root[(i-1)*l+1]<>root[i*l+1] then continue; s:=(i-1)*l+1-similar(n-(i-1)*l+1,n-i*l+1,nmin,nrank,nheight); k:=similar(s,s+l,min,rank,height)+l; q:=k div l; if q>=max then begin p:=similardict(s,s+k-q*l); if (q>max)or ((q=max)and(rank[where]>rank[p])) then begin max:=q; where:=p; long:=l; end; end; end; write('Case ',t,': '); for i:=where to where+max*long-1 do write(root[i]); writeln; until false; end.