登 录
非常恶心的一道题目,看了罗的论文,其中并没有说最小的字典序怎么处理,我整整写了3个RMQ,哎哟~~
总之就是先枚举单个循环节的长度,然后再枚举,找公共前缀(后缀),关于字典序还要写另外一个RMQ。。
100行的代码对于我这种喜欢缩行的人已经很恐怖了。。
program ex3;const ln2=1/ln(2); type arr=array[0..100001] of longint; var x,y,r,sa,c:arr; q,p,v:array[0..18] of arr; i,j,k,l,n,t,l1,l2,o1,o2,a1,a2,a3,max,ans1,ans2,ans3,task:longint; a:ansistring; function min(a,b:longint):longint; begin if a>b then min:=b else min:=a end; procedure sort(var a:arr;b:arr); begin fillchar(c,sizeof(c),0); for i:=1 to n do inc(c[a[i]+1]); for i:=1 to max do inc(c[i],c[i-1]); for i:=1 to n do begin inc(c[a[b[i]]]);sa[c[a[b[i]]]]:=b[i]; end; end; begin readln(a); while a<>'#' do begin n:=length(a);inc(task); for i:=1 to n do begin sa[i]:=i;v[0,i]:=i; r[i]:=ord(a[i])-ord('a')+1; end; max:=28;l:=1; while max<>n do begin for i:=1 to n do if i+l<=n then y[i]:=r[i+l] else y[i]:=0; x:=r;sort(y,sa);sort(x,sa); max:=0;l:=l*2; for i:=1 to n do begin inc(max,ord((x[sa[i]]<>x[sa[i-1]]) or(y[sa[i]]<>y[sa[i-1]]))); r[sa[i]]:=max; end; end; l:=0; for i:=1 to n do begin dec(l,ord(l<>0)); j:=i;k:=sa[r[i]-1]; if r[i]=1 then continue; while (j+l<=n)and(k+l<=n)and(a[j+l]=a[k+l]) do inc(l); p[0,r[i]-1]:=l; end; l:=0; for i:=n downto 1 do begin dec(l,ord(l<>0)); j:=i;k:=sa[r[i]+1]; if r[i]=n then continue; while (j-l>0)and(k-l>0)and(a[j-l]=a[k-l]) do inc(l); q[0,r[i]]:=l; end; for i:=1 to trunc(ln(n)*ln2-1e-9)+1 do for j:=1 to n do begin k:=j+1<<(i-1); if k>n then k:=n; q[i,j]:=q[i-1,j]; p[i,j]:=p[i-1,j]; v[i,j]:=v[i-1,j]; if q[i-1,k]<q[i,j] then q[i,j]:=q[i-1,k]; if p[i-1,k]<p[i,j] then p[i,j]:=p[i-1,k]; if r[v[i-1,k]]<r[v[i,j]] then v[i,j]:=v[i-1,k]; end; ans2:=sa[1]; ans1:=1;ans3:=1; for l:=1 to n>>1 do if n div l>=ans1 then for i:=1 to n div l-1 do begin o1:=r[i*l];o2:=r[i*l+l]; if o1>o2 then begin j:=o1;o1:=o2;o2:=j; end; t:=trunc(ln(o2-o1)*ln2); l1:=min(p[t,o1],p[t,o2-(1<<t)]); l2:=min(q[t,o1],q[t,o2-(1<<t)]); k:=l1+l2-1; if (k div l+1>=ans1)and(k>=l) then begin a1:=k div l+1;a3:=l; o1:=i*l-l2+1;o2:=o1+k-(a1-1)*l; if o1=o2 then t:=0 else t:=trunc(ln(o2-o1)*ln2); a2:=v[t,o1]; if r[v[t,o2-(1<<t)+1]]<r[a2] then a2:=v[t,o2-(1<<t)+1]; if (a1>ans1)or(a1=ans1)and(r[a2]<r[ans2]) then begin ans1:=a1;ans2:=a2;ans3:=a3; end; end; end; writeln('Case ',task,': ',copy(a,ans2,ans3*ans1)); readln(a); end; end.
抱歉!评论已关闭.