题意:将一个长度为2n(复制粘贴后)的字符串的所有长度为n的后缀从小到大排序,并依次输出它们的最后一个字母。
n<=100000
思路:裸SA,模板真难背
P党不得不写成C++风格
1 var ch:array[0..300000]of char; 2 a,x,y,wc,wd,sa:array[0..300000]of longint; 3 n,i,m:longint; 4 tmp:char; 5 6 function cmp(a,b,l:longint):boolean; 7 begin 8 exit((y[a]=y[b])and(y[a+l]=y[b+l])); 9 end; 10 11 procedure swap(var x,y:longint); 12 var t:longint; 13 begin 14 t:=x; x:=y; y:=t; 15 end; 16 17 procedure getsa; 18 var i,j,p:longint; 19 begin 20 for i:=0 to n-1 do 21 begin 22 x[i]:=a[i]; 23 inc(wc[a[i]]); 24 end; 25 for i:=1 to m do wc[i]:=wc[i-1]+wc[i]; 26 for i:=n-1 downto 0 do 27 begin 28 dec(wc[x[i]]); 29 sa[wc[x[i]]]:=i; 30 end; 31 32 j:=1; p:=1; 33 while p<n do 34 begin 35 p:=0; 36 for i:=n-j to n-1 do 37 begin 38 y[p]:=i; inc(p); 39 end; 40 for i:=0 to n-1 do 41 if sa[i]>=j then begin y[p]:=sa[i]-j; inc(p); end; 42 // for i:=0 to n-1 do writeln(y[i]); 43 for i:=0 to n-1 do wd[i]:=x[y[i]]; 44 for i:=0 to m do wc[i]:=0; 45 for i:=0 to n-1 do inc(wc[wd[i]]); 46 for i:=1 to m do wc[i]:=wc[i-1]+wc[i]; 47 for i:=n-1 downto 0 do 48 begin 49 dec(wc[wd[i]]); 50 sa[wc[wd[i]]]:=y[i]; 51 end; 52 53 for i:=0 to n do swap(x[i],y[i]); 54 55 p:=1; x[sa[0]]:=0; 56 for i:=1 to n-1 do 57 begin 58 if cmp(sa[i-1],sa[i],j) then x[sa[i]]:=p-1 59 else begin x[sa[i]]:=p; inc(p); end; 60 end; 61 62 j:=j*2; 63 m:=p; 64 end; 65 end; 66 67 68 begin 69 assign(input,‘bzoj1031r.in‘); reset(input); 70 assign(output,‘bzoj1031r.out‘); rewrite(output); 71 while not eoln do 72 begin 73 read(tmp); 74 inc(n); 75 ch[n]:=tmp; 76 end; 77 for i:=1 to n do a[i-1]:=ord(ch[i]); 78 for i:=n to n*2-1 do a[i]:=a[i-n]; 79 n:=n*2+1; m:=300; 80 getsa; 81 for i:=1 to n-1 do 82 if sa[i]<(n>>1) then 83 begin 84 if sa[i]=0 then write(chr(a[n-2])) 85 else write(chr(a[sa[i]-1])); 86 end; 87 close(input); 88 close(output); 89 90 91 end.
时间: 2024-11-24 04:18:24