zoukankan      html  css  js  c++  java
  • 【BZOJ2342】双倍回文(manacher,并查集)

    题意:

    思路:From http://blog.sina.com.cn/s/blog_8d5d2f04010196bh.html

    首先我可以看出:
    (1)我们找到的串的本身也是一个回文串(显然)
    (2)这个回文串的长度一定是偶数(显然)
    (3)左右两个串一定也是偶数长度的回文串(显然)
     
    那么我们先用manacher处理出以每个字符为中心的回文串长度
    由于我们所需处理的这些串的长度都为偶数,所以这些串的中心都在manacher时的那些填充字符上(显然)
     
    那么我们就先枚举大串的中心i,设左边小串的中心为j
    那么j+rad[j]>=i   (rad[]为manacher中处理出的数组)
    由于左边一定是回文串,那么rad[j]就应该要覆盖到i(不然怎么保证左边是回文串),而如果左边得到保证,那么右边也一定符合条件(对称)
    所以我们就只需求出满足条件的最左侧的j
     
    然后我们对j也有一个枚举范围,那就是在i的回文串范围内,并且还在i-rad[i]/2 ~ i 之间,不然不够
     
    这样我们就可以初步得出一个枚举算法,那就是对于每个i,在一定范围内枚举j,找最优解
    据说这个算法是可过的,但是复杂度。。。。似乎不是太乐观
     
    于是需要优化
    该优化其实也是显然的
     
    如果我们曾枚举过一个j,它不能覆盖到当前枚举的i(也就是j+rad[j]
    那么这个j,用一定不能覆盖到i+1(显然)
    也就是说这个j在之后的计算中都没有用了,我们就不需要枚举了
     
    这样我们就可以在枚举j的时候一段一段的跳,以降低复杂度
    而实现这个过程,我们可以用并查集
    每次都将没用的j的父亲指向j+1,然后跳到getfather(j+1)
    这样就轻松完成了分段跳这个优化
     
    最后在分析一下复杂度
    (1)manacher  O(n)
    (2)并查集    O(nα(n))
    (3)每个点最多被删n次 O(n)
    (4)每个点最多被利用一次 O(n)
    (5)每个点最多被枚举一次 O(n)
    这个复杂度真的是怎么算怎么舒心,而且代码很好实现
     1 var f,p:array[0..1100000]of longint;
     2     a:array[0..1100000]of char;
     3     len,i,n,mx,id,ans,j:longint;
     4     ch:ansistring;
     5 
     6 function min(x,y:longint):longint;
     7 begin
     8  if x<y then exit(x);
     9  exit(y);
    10 end;
    11 
    12 function max(x,y:longint):longint;
    13 begin
    14  if x>y then exit(x);
    15  exit(y);
    16 end;
    17 
    18 function find(k:longint):longint;
    19 begin
    20  if f[k]<>k then f[k]:=find(f[k]);
    21  find:=f[k];
    22 end;
    23 
    24 begin
    25  assign(input,'bzoj2342.in'); reset(input);
    26  assign(output,'bzoj2342.out'); rewrite(output);
    27  readln(len);
    28  readln(ch);
    29  n:=2; a[1]:='@'; a[2]:='#';
    30  for i:=1 to len do
    31  begin
    32   inc(n); a[n]:=ch[i];
    33   inc(n); a[n]:='#';
    34  end;
    35  inc(n); a[n]:='$';
    36  mx:=0; id:=0;
    37  for i:=2 to n-1 do
    38  begin
    39   if mx>i then p[i]:=min(p[id*2-i],mx-i)
    40    else p[i]:=1;
    41   while a[i-p[i]]=a[i+p[i]] do inc(p[i]);
    42   if p[i]+i>mx then
    43   begin
    44    mx:=p[i]+i;
    45    id:=i;
    46   end;
    47  end;
    48  for i:=2 to n-1 do
    49   if a[i]='#' then f[i]:=i
    50    else f[i]:=i+1;
    51  i:=2; j:=2;
    52  repeat
    53   i:=i+2;
    54   if i>n then break;
    55   j:=find(max(i-p[i] div 2,2));
    56   while (j<i)and(j+p[j]<i) do
    57   begin
    58    f[j]:=find(j+1);
    59    j:=f[j];
    60   end;
    61   if j<i then ans:=max(ans,(i-j)*2);
    62  until i>n;
    63  writeln(ans);
    64  close(input);
    65  close(output);
    66 end.
  • 相关阅读:
    C
    A
    L
    G
    关于html()、val()、text()
    EL表达式
    JSON书写格式示例
    Servlet获取项目名的方法
    修改完Servlet后不用重启项目的设置方法
    浮动
  • 原文地址:https://www.cnblogs.com/myx12345/p/6704292.html
Copyright © 2011-2022 走看看