zoukankan      html  css  js  c++  java
  • bzoj2119

    题意就是差分后求形如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
  • 相关阅读:
    npm ci fast install All In One
    WebGL & CG All In One
    StackOverflow winterbash 2021 All In One
    jira advanced searching All In One
    localStorage undefined bug All In One
    vcharts bug All In One
    crypto.getRandomValues & Math.random All In One
    Web 3D 技术 All In One
    企业微信如何设置用户当前状态 All In One
    parent.postMessage bug All In One
  • 原文地址:https://www.cnblogs.com/phile/p/4665407.html
Copyright © 2011-2022 走看看