很久以前写的,忘补结题报告了
两串相连中间用特殊的分隔符
然后求height,由于要求求公共子串大于等于k的个数,并且只要位置不同即可
因此不难想到在名次上对height分组,一组内的height保证>=k
下面就是在组内统计的问题了
然后还是不难发现,分别在AB串中的后缀i,j,他们能产生2*[LCP(i,j)-k+1]个公共子串
然后那个著名的性质LCP(i,j)=min(h[rank[i]+1]~h[rank[j]]) (令rank[i]<rank[j])
不难想到维护一个单调增的队列,遇到在B串就统计并维护,遇到在A串就维护
然后再反过来做一遍
具体维护单调队列见程序,否则感觉讲不清
1 type node=record 2 h,s:longint; 3 end; 4 var s,ss:ansistring; 5 h,sa,sum,y,x,rank:array[0..201000] of longint; 6 n,m,i,j,loc,p,k,t,f:longint; 7 q:array[0..2010000] of node; 8 w,ans:int64; 9 10 begin 11 readln(k); 12 while k<>0 do 13 begin 14 readln(s); 15 loc:=length(s)+1; 16 readln(ss); 17 s:=s+' '+ss; 18 n:=length(s); 19 fillchar(sum,sizeof(sum),0); 20 for i:=1 to n do 21 begin 22 y[i]:=ord(s[i]); 23 inc(sum[y[i]]); 24 end; 25 m:=255; 26 for i:=2 to m do 27 inc(sum[i],sum[i-1]); 28 for i:=n downto 1 do 29 begin 30 sa[sum[y[i]]]:=i; 31 dec(sum[y[i]]); 32 end; 33 p:=1; 34 rank[sa[1]]:=1; 35 for i:=2 to n do 36 begin 37 if y[sa[i]]<>y[sa[i-1]] then inc(p); 38 rank[sa[i]]:=p; 39 end; 40 m:=p; 41 j:=1; 42 while m<n do 43 begin 44 y:=rank; 45 fillchar(sum,sizeof(sum),0); 46 p:=0; 47 for i:=n-j+1 to n do 48 begin 49 inc(p); 50 x[p]:=i; 51 end; 52 for i:=1 to n do 53 if sa[i]>j then 54 begin 55 inc(p); 56 x[p]:=sa[i]-j; 57 end; 58 for i:=1 to n do 59 begin 60 rank[i]:=y[x[i]]; 61 inc(sum[rank[i]]); 62 end; 63 for i:=2 to m do 64 inc(sum[i],sum[i-1]); 65 for i:=n downto 1 do 66 begin 67 sa[sum[rank[i]]]:=x[i]; 68 dec(sum[rank[i]]); 69 end; 70 p:=1; 71 rank[sa[1]]:=1; 72 for i:=2 to n do 73 begin 74 if (y[sa[i]]<>y[sa[i-1]]) or (y[sa[i]+j]<>y[sa[i-1]+j]) then inc(p); 75 rank[sa[i]]:=p; 76 end; 77 j:=j shl 1; 78 m:=p; 79 end; 80 h[1]:=0; 81 p:=0; 82 for i:=1 to n do 83 begin 84 if rank[i]=1 then continue; 85 j:=sa[rank[i]-1]; 86 while s[i+p]=s[j+p] do inc(p); 87 h[rank[i]]:=p; 88 if p>0 then dec(p); 89 end; 90 91 ans:=0; 92 t:=0; 93 f:=0; 94 w:=0; 95 if sa[1]<loc then 96 begin 97 w:=w+h[2]-k+1; 98 q[t].h:=h[2]; 99 q[t].s:=1; 100 inc(t); 101 end; 102 for i:=2 to n do 103 begin 104 if h[i]>=k then 105 begin 106 if sa[i]<loc then 107 begin 108 p:=1; 109 w:=w+h[i+1]-k+1; //w维护组内到下一个在B中的后缀(LCP-k+1)和 110 end 111 else if sa[i]>loc then 112 begin 113 ans:=ans+w; 114 if i=n then continue; 115 p:=0; //这里注意,这是B串的后缀,不能和下一个B串后缀形成公共子串 116 end; 117 while (f<t) and (q[t-1].h>=h[i+1]) do //队中height比当前大直接退,因为它的height一定不是LCP 118 begin 119 w:=w-(q[t-1].h-h[i+1])*q[t-1].s; //s域维护是队列中当前元素到队中前一个元素之间有多少比它height大 120 //这里显然之前height比当前大的元素和下一个B串后缀可能的LCP都应当是当前h[i+1] 121 p:=p+q[t-1].s; 122 dec(t); 123 end; 124 if p>0 then 125 begin 126 q[t].h:=h[i+1]; 127 q[t].s:=p; 128 inc(t); 129 end; 130 end 131 else begin 132 t:=0; 133 w:=0; 134 f:=0; 135 if sa[i]<loc then 136 begin 137 q[t].h:=h[i+1]; 138 q[t].s:=1; 139 w:=h[i+1]-k+1; 140 inc(t); 141 end; 142 end; 143 end; 144 145 t:=0; 146 f:=0; 147 w:=0; 148 if sa[1]<loc then 149 begin 150 w:=w+h[2]-k+1; 151 q[t].h:=h[2]; 152 q[t].s:=1; 153 inc(t); 154 end; 155 for i:=2 to n do 156 begin 157 if h[i]>=k then 158 begin 159 if sa[i]>loc then 160 begin 161 p:=1; 162 w:=w+h[i+1]-k+1; 163 end 164 else if sa[i]<loc then 165 begin 166 ans:=ans+w; 167 if i=n then continue; 168 p:=0; 169 end; 170 while (f<t) and (q[t-1].h>=h[i+1]) do 171 begin 172 w:=w-(q[t-1].h-h[i+1])*q[t-1].s; 173 p:=p+q[t-1].s; 174 dec(t); 175 end; 176 if p>0 then 177 begin 178 q[t].h:=h[i+1]; 179 q[t].s:=p; 180 inc(t); 181 end; 182 end 183 else begin 184 t:=0; 185 w:=0; 186 f:=0; 187 if sa[i]>loc then 188 begin 189 q[t].h:=h[i+1]; 190 q[t].s:=1; 191 w:=h[i+1]-k+1; 192 inc(t); 193 end; 194 end; 195 end; 196 writeln(ans); 197 readln(k); 198 end; 199 end.