题意:求字符串的可重叠的k次最长重复子串
n<=20000 a[i]<=1000000
思路:后缀数组+二分答案x,根据height分组,每组之间的height>=x
因为可以重叠,所以只要判断是否有一组的height个数>=k即可
1 var sa,rank,x,y,a,wc,wd,height:array[0..1100000]of longint; 2 n,m,i,l,r,mid,last,k1:longint; 3 4 procedure swap(var x,y:longint); 5 var t:longint; 6 begin 7 t:=x; x:=y; y:=t; 8 end; 9 10 function cmp(a,b,l:longint):boolean; 11 begin 12 exit((y[a]=y[b])and(y[a+l]=y[b+l])); 13 end; 14 15 procedure getsa(n:longint); 16 var i,j,p:longint; 17 begin 18 for i:=0 to n-1 do 19 begin 20 x[i]:=a[i]; 21 inc(wc[a[i]]); 22 end; 23 for i:=1 to m-1 do wc[i]:=wc[i-1]+wc[i]; 24 for i:=n-1 downto 0 do 25 begin 26 dec(wc[x[i]]); 27 sa[wc[x[i]]]:=i; 28 end; 29 j:=1; p:=1; 30 while p<n do 31 begin 32 p:=0; 33 for i:=n-j to n-1 do 34 begin 35 y[p]:=i; inc(p); 36 end; 37 for i:=0 to n-1 do 38 if sa[i]>=j then begin y[p]:=sa[i]-j; inc(p); end; 39 for i:=0 to n-1 do wd[i]:=x[y[i]]; 40 for i:=0 to m-1 do wc[i]:=0; 41 for i:=0 to n-1 do inc(wc[wd[i]]); 42 for i:=1 to m-1 do wc[i]:=wc[i-1]+wc[i]; 43 for i:=n-1 downto 0 do 44 begin 45 dec(wc[wd[i]]); 46 sa[wc[wd[i]]]:=y[i]; 47 end; 48 for i:=0 to n do swap(x[i],y[i]); 49 p:=1; x[sa[0]]:=0; 50 for i:=1 to n-1 do 51 if cmp(sa[i-1],sa[i],j) then x[sa[i]]:=p-1 52 else begin x[sa[i]]:=p; inc(p); end; 53 j:=j*2; 54 m:=p; 55 end; 56 end; 57 58 procedure getheight(n:longint); 59 var i,k,j:longint; 60 begin 61 for i:=1 to n do rank[sa[i]]:=i; 62 k:=0; 63 for i:=0 to n-1 do 64 begin 65 if k>0 then dec(k); 66 j:=sa[rank[i]-1]; 67 while a[i+k]=a[j+k] do inc(k); 68 height[rank[i]]:=k; 69 end; 70 end; 71 72 function isok(x:longint):boolean; 73 var s,i:longint; 74 begin 75 s:=1; 76 for i:=1 to n do 77 begin 78 if height[i]<x then 79 begin 80 if s>=k1 then exit(true); 81 s:=1; 82 end 83 else inc(s); 84 end; 85 if s>=k1 then exit(true); 86 exit(false); 87 end; 88 89 begin 90 91 while not eof do 92 begin 93 fillchar(a,sizeof(a),0); 94 fillchar(sa,sizeof(sa),0); 95 fillchar(rank,sizeof(rank),0); 96 fillchar(x,sizeof(x),0); 97 fillchar(y,sizeof(y),0); 98 fillchar(height,sizeof(height),0); 99 fillchar(wc,sizeof(wc),0); 100 fillchar(wd,sizeof(wd),0); 101 readln(n,k1); 102 if n=0 then break; 103 for i:=0 to n-1 do 104 begin 105 read(a[i]); 106 inc(a[i]); 107 end; 108 a[n]:=0; m:=1000001; 109 getsa(n+1); 110 getheight(n); 111 l:=1; r:=n; last:=0; 112 while l<=r do 113 begin 114 mid:=(l+r)>>1; 115 if isok(mid) then begin last:=mid; l:=mid+1; end 116 else r:=mid-1; 117 end; 118 writeln(last); 119 // for i:=0 to n do writeln(height[i]); 120 end; 121 122 123 124 end. 125
时间: 2024-10-05 04:44:43