题意就是差分后求形如ABA的串的个数,B的长度为M

这是2011国家集训队互测的试题,是道好题,我直接给出出题人的题解吧:

对于这种在线性序列上的组合计数问题,我们很容易想到一个工具:分治!分治算法在形如快速排序等地方能顺利优化算法,我们尝试将其运用至本题中。

不妨设过程F(Left,Right)可以统计在区间[Left,Right]中满足条件的子序列的个数。

Mid为区间[Left,Right]的中点由于分治执行,我们不需要统计那些属于[Left,Mid],[Mid+1,Right]中的子序列,剩下的我们分两种情况讨论。

1、 点MidQ。这种情况由于|Q|非常小,我们可以直接枚举Q的位置,然后我们可以穷举A部分长度,然后后缀数组+RMQ解决这个问题

    此时算法多了一个系数M,不过整体仍然可以在O(NMLogN)的复杂度内完成。

2、 点MidQ,这种情况就比较麻烦了,可以表示成如下示意图:

由于Mid的存在,P2被分割成了3份,由于P1=P2,我们把P1也分割成3份,经过仔细观察,我们发现只需要枚举红线的位置即可解决此部分的统计问题。黄色部分的最大匹配值可以通过将整个Mid左面的部分倒置后求LCP可得。而Mid以及绿色部分的匹配值可以直接通过后缀数组+RMQ求的。知道了绿色与黄色部分的最大值后,那么Q的位置个数也可以相应得出,问题得到解决,此部分复杂度为O(NLogN)

方法三总复杂度为O(NMLogN),为一个非常优秀的算法。

 

  1 const eps=1e-8;
  2 var s,h,sa,rank:array[0..100010,0..1] of longint;
  3     sum,a,b,x,y:array[0..100010] of longint;
  4     f:array[0..100010,0..20,0..1] of longint;
  5     d:array[0..20] of longint;
  6     t,mx,ans,i,n,m:longint;
  7 
  8 procedure swap(var a,b:longint);
  9   var c:longint;
 10   begin
 11     c:=a;
 12     a:=b;
 13     b:=c;
 14   end;
 15 
 16 function min(a,b:longint):longint;
 17   begin
 18     if a>b then exit(b) else exit(a);
 19   end;
 20 
 21 procedure suffix(k:longint);
 22   var i,j,m,p:longint;
 23   begin
 24     fillchar(sum,sizeof(sum),0);
 25     for i:=1 to n do
 26       inc(sum[s[i,k]]);
 27     for i:=1 to mx do
 28       inc(sum[i],sum[i-1]);
 29     for i:=n downto 1 do
 30     begin
 31       sa[sum[s[i,k]],k]:=i;
 32       dec(sum[s[i,k]]);
 33     end;
 34     p:=1;
 35     rank[sa[1,k],k]:=1;
 36     for i:=2 to n do
 37     begin
 38       if s[sa[i,k],k]<>s[sa[i-1,k],k] then inc(p);
 39       rank[sa[i,k],k]:=p;
 40     end;
 41     m:=p;
 42     j:=1;
 43     while m<n do
 44     begin
 45       for i:=1 to n do
 46       begin
 47         y[i]:=rank[i,k];
 48         sum[i]:=0;
 49       end;
 50       p:=0;
 51       for i:=n-j+1 to n do
 52       begin
 53         inc(p);
 54         x[p]:=i;
 55       end;
 56       for i:=1 to n do
 57         if sa[i,k]>j then
 58         begin
 59           inc(p);
 60           x[p]:=sa[i,k]-j;
 61         end;
 62 
 63       for i:=1 to n do
 64       begin
 65         a[i]:=y[x[i]];
 66         inc(sum[a[i]]);
 67       end;
 68       for i:=1 to m do
 69         inc(sum[i],sum[i-1]);
 70       for i:=n downto 1 do
 71       begin
 72         sa[sum[a[i]],k]:=x[i];
 73         dec(sum[a[i]]);
 74       end;
 75       p:=1;
 76       rank[sa[1,k],k]:=1;
 77       for i:=2 to n do
 78       begin
 79         if (y[sa[i,k]]<>y[sa[i-1,k]]) or (y[sa[i,k]+j]<>y[sa[i-1,k]+j]) then inc(p);
 80         rank[sa[i,k],k]:=p;
 81       end;
 82       m:=p;
 83       j:=j shl 1;
 84     end;
 85     h[1,k]:=0;
 86     p:=0;
 87     for i:=1 to n do
 88     begin
 89       if rank[i,k]=1 then continue;
 90       j:=sa[rank[i,k]-1,k];
 91       while (i+p<=n) and (j+p<=n) and (s[i+p,k]=s[j+p,k]) do inc(p);
 92       h[rank[i,k],k]:=p;
 93       if p>0 then dec(p);
 94     end;
 95     for i:=1 to n do
 96       f[i,0,k]:=h[i,k];
 97     for j:=1 to t do
 98       for i:=1 to n do
 99         if i+d[j]-1<=n then
100           f[i,j,k]:=min(f[i,j-1,k],f[i+d[j-1],j-1,k])
101         else break;
102   end;
103 
104 function ask(l,r,k:longint):longint;
105   var p:longint;
106   begin
107     if l>r then swap(l,r);
108     inc(l);
109     p:=trunc(ln(r-l+1)/ln(2)+eps);
110     exit(min(f[l,p,k],f[r-d[p]+1,p,k]));
111   end;
112 
113 procedure work(l,r:longint);
114   var mid,i,j,x,y:longint;
115   begin
116     if r-l+1<m+2 then exit;
117     mid:=(l+r) shr 1;
118     for i:=mid-m+1 to mid do
119       for j:=i-1 downto l do
120       begin
121         if r-(i+m)+1<i-j then break;
122         if ask(rank[j,0],rank[i+m,0],0)>=i-j then inc(ans);
123       end;
124 
125     for i:=l to mid-m-1 do
126     begin
127       x:=min(ask(rank[i,0],rank[mid,0],0),mid-i-m);
128       if (x<1) then continue;
129       y:=ask(rank[n+1-i,1],rank[n+1-mid,1],1);
130       y:=min(y-1,min(i-l,mid-i-m-1));
131       if y<mid-i-m-x then continue;
132       ans:=ans+min(x,y-(mid-i-m-x)+1);
133     end;
134     for i:=mid+m+1 to r do
135     begin
136       y:=min(i-mid-m,ask(rank[n+1-i,1],rank[n+1-mid,1],1));
137       if y<1 then continue;
138       x:=ask(rank[i+1,0],rank[mid+1,0],0);
139       x:=min(x,min(r-i,i-mid-m-1));
140       if x<i-mid-m-y then continue;
141       ans:=ans+min(y,x-(i-mid-m-y)+1);
142     end;
143     work(l,mid-1);
144     work(mid+1,r);
145   end;
146 
147 procedure sort(l,r:longint);
148   var i,j,x:longint;
149   begin
150     i:=l;
151     j:=r;
152     x:=a[(l+r) shr 1];
153     repeat
154       while a[i]<x do inc(i);
155       while x<a[j] do dec(j);
156       if not(i>j) then
157       begin
158         swap(a[i],a[j]);
159         swap(b[i],b[j]);
160         inc(i);
161         dec(j);
162       end;
163     until i>j;
164     if l<j then sort(l,j);
165     if i<r then sort(i,r);
166   end;
167 
168 begin
169   readln(n,m);
170   for i:=1 to n do
171     read(a[i]);
172   dec(n);
173   for i:=1 to n do
174     s[i,0]:=a[i+1]-a[i];
175 
176   for i:=1 to n do
177   begin
178     a[i]:=s[i,0];
179     b[i]:=i;
180   end;
181   sort(1,n);
182   mx:=1;
183   s[b[1],0]:=1;
184   for i:=2 to n do
185   begin
186     if a[i]<>a[i-1] then inc(mx);
187     s[b[i],0]:=mx;
188   end;
189   for i:=1 to n do
190     s[i,1]:=s[n+1-i,0];
191   t:=trunc(ln(n)/ln(2)+eps);
192   d[0]:=1;
193   for i:=1 to t do
194     d[i]:=d[i-1]*2;
195   suffix(0);
196   suffix(1);
197   work(1,n);
198   writeln(ans);
199 end.
View Code

 

posted on 2015-07-21 19:26  acphile  阅读(394)  评论(0编辑  收藏  举报