都LCP了很显然是要用到后缀数组的

显然前面的那个东西是可以直接算出来的

关键在于LCP的和怎么快速的计算

不难想到穷举height[i],然后判断这个height[i]可能成为多少对后缀的LCP

考虑到LCP(i,j)=min(height[rank[i]+1~rank[j]]) 假定rank[i]<rank[j];

假设height[l]是左边第一个小于height[i]的,height[r]是右边第一个小于height[i]的

则height[i]是(i-l)(r-i)对后缀的LCP

但这样有一个问题,相同height可能会被重复计算

为了避免重复,我们定义height[r]是右边第一个不大于height[i]的

这样就有两种方法来实现

第一种是二分+rmq,但不幸的是我竟然写超时,而且我觉得容易出错

第二种是利用单调队列,我们把height[i]对应的l,r定义为左右边界,记为l[i],r[i];

计算左边界和右边界是相似的,这里我们讨论左边界

假如height[j]<=height[k] (j>k) 那么对于之后的height[i],

要么能延伸到k之前(height[i]<=height[j]),要么只能左边界就是j(height[i]>height[j]),不用比较height[k]

显然我们要维护一个单调不降的队列就行了

最后计算的时候注意用int64

  1 var rank,sa,y,q,x,sum,h,l,r:array[0..600010] of longint;
  2     s:ansistring;
  3     i,n,m,p,j,t:longint;
  4     ans,z:int64;
  5 
  6 function min(a,b:longint):longint;
  7   begin
  8     if a>b then exit(b) else exit(a);
  9   end;
 10 
 11 procedure suffix;
 12   var i,j,p:longint;
 13   begin
 14     for i:=1 to n do
 15     begin
 16       y[i]:=ord(s[i]);
 17       inc(sum[y[i]]);
 18     end;
 19     m:=255;
 20     for i:=1 to m do
 21       inc(sum[i],sum[i-1]);
 22     for i:=n downto 1 do
 23     begin
 24       sa[sum[y[i]]]:=i;
 25       dec(sum[y[i]]);
 26     end;
 27     p:=1;
 28     rank[sa[1]]:=1;
 29     for i:=2 to n do
 30     begin
 31       if y[sa[i]]<>y[sa[i-1]] then inc(p);
 32       rank[sa[i]]:=p;
 33     end;
 34     m:=p;
 35     j:=1;
 36     while m<n do
 37     begin
 38       fillchar(sum,sizeof(sum),0);
 39       y:=rank;
 40       p:=0;
 41       for i:=n-j+1 to n do
 42       begin
 43         inc(p);
 44         x[p]:=i;
 45       end;
 46       for i:=1 to n do
 47         if sa[i]>j then
 48         begin
 49           inc(p);
 50           x[p]:=sa[i]-j;
 51         end;
 52 
 53       for i:=1 to n do
 54       begin
 55         rank[i]:=y[x[i]];
 56         inc(sum[rank[i]]);
 57       end;
 58       for i:=1 to m do
 59         inc(sum[i],sum[i-1]);
 60       for i:=n downto 1 do
 61       begin
 62         sa[sum[rank[i]]]:=x[i];
 63         dec(sum[rank[i]]);
 64       end;
 65       p:=1;
 66       rank[sa[1]]:=1;
 67       for i:=2 to n do
 68       begin
 69         if (y[sa[i]]<>y[sa[i-1]]) or (y[sa[i]+j]<>y[sa[i-1]+j]) then inc(p);
 70         rank[sa[i]]:=p;
 71       end;
 72       m:=p;
 73       j:=j shl 1;
 74     end;
 75     h[1]:=0;
 76     p:=0;
 77     for i:=1 to n do
 78     begin
 79       if rank[i]=1 then continue;
 80       j:=sa[rank[i]-1];
 81       while (i+p<=n) and (j+p<=n) and (s[i+p]=s[j+p]) do inc(p);
 82       h[rank[i]]:=p;
 83       if p>0 then dec(p);
 84     end;
 85   end;
 86 
 87 function calc(i,x,y:int64):int64;
 88   begin
 89     exit(2*h[i]*(i-x)*(y-i));
 90   end;
 91 
 92 begin
 93   readln(s);
 94   n:=length(s);
 95   suffix;
 96   z:=n;
 97   ans:=(z+1)*z div 2*(z-1);
 98   t:=0;
 99   for i:=2 to n do
100   begin
101     while (t>0) and (h[q[t]]>=h[i]) do dec(t);
102     if t=0 then l[i]:=1
103     else l[i]:=q[t];
104     inc(t);
105     q[t]:=i;
106   end;
107   t:=0;
108   for i:=n downto 2 do
109   begin
110     while (t>0) and (h[q[t]]>h[i]) do dec(t);  //注意右边界是第一个不大于的height,防止重复
111     if t=0 then r[i]:=n+1
112     else r[i]:=q[t];
113     inc(t);
114     q[t]:=i;
115   end;
116   for i:=2 to n do
117     ans:=ans-calc(i,l[i],r[i]);
118   writeln(ans);
119 end.
View Code

 

posted on 2014-08-21 19:57  acphile  阅读(151)  评论(0编辑  收藏  举报