zoukankan      html  css  js  c++  java
  • bzoj2342

    shoi题目好坑爹

    首先自己测发现这道题如果用后缀数组+rmq处理每个点回文串能延伸长度的话会TLE

    (当然我用的是倍增+ST的方法,如果用三分构建后缀数组+笛卡尔树处理rmq我就不知道了);

    关于最长回文子串的问题有一个更快的算法叫manacher,实现简单也好理解

    这个算法的优点在于它在每两个字符之间插入一个新的字符#,使得所有的回文子串都变成了奇数长度的

    具体的介绍:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824

    求出以每个字符为中心的回文串最长延伸长度p[i]后(注意p[i]-1就是在原串中以该字符为中心的最长回文子串)

    我们下面就要来找双倍回文

    首先,穷举中心字符我们肯定是穷举“#”而不穷举字母

    不难想到一种O(n2)的做法,先穷举双倍回文的中心,在穷举左半边回文的中心判断是否存在可行解

    (事实上,左边穷举的时候我们只要从i-p[i]/2找就可以了

    但实际上,随着我们向右穷举双倍回文的中心,左边一些点穷举了一次是肯定是不用再穷举的,

    我们可以考虑用并查集优化

     1 var p,fa:array[0..1000010] of longint;
     2     j,l,n,k,i,ans,right:longint;
     3     s:array[0..1000010] of char;
     4     ch:char;
     5 
     6 function min(a,b:longint):longint;
     7   begin
     8     if a>b then exit(b) else exit(a);
     9   end;
    10 
    11 function max(a,b:longint):longint;
    12   begin
    13     if a>b then exit(a) else exit(b);
    14   end;
    15 
    16 function getf(x:longint):longint;
    17   begin
    18     if x<>fa[x] then fa[x]:=getf(fa[x]);
    19     exit(fa[x]);
    20   end;
    21 
    22 begin
    23   readln(l);
    24   s[0]:='$';
    25   s[1]:='#';
    26   for i:=1 to l do
    27   begin
    28     read(ch);
    29     s[i*2]:=ch;
    30     s[i*2+1]:='#';
    31   end;
    32   n:=2*l+1;
    33   k:=0;
    34   right:=0;
    35   for i:=1 to n do
    36   begin
    37     if right>i then
    38       p[i]:=min(p[2*k-i],right-i)
    39     else p[i]:=1;
    40     while (s[i+p[i]]=s[i-p[i]]) do inc(p[i]);
    41     if p[i]+i>right then
    42     begin
    43       right:=p[i]+i;
    44       k:=i;
    45     end;
    46   end;
    47   for i:=1 to n do
    48     if s[i]='#' then fa[i]:=i else fa[i]:=i+1;
    49   for i:=3 to n do
    50   begin
    51     if i mod 2=1 then
    52     begin
    53       j:=getf(max(i-p[i] div 2,1));
    54       while (j<i) and (j+p[j]-1<i) do
    55       begin
    56         fa[j]:=getf(j+1);
    57         j:=fa[j];
    58       end;
    59       if j<i then ans:=max(ans,(i-j)*2);
    60     end;
    61   end;
    62   writeln(ans);
    63 end.
    View Code
  • 相关阅读:
    RAID介绍,RAID5,10制作与损坏恢复
    ELK 安装过程
    centos 系统 yum安装软件报错
    linux系统磁盘分区
    python实现遍历两个文件夹,比对文件异常,生成比对报告功能
    win10新装系统,显卡风扇转动,链接正常开机,但设备管理器如果显示,无法更新驱动
    navicat premium 破解,无限试用方法
    安装vmware workstations 12 +ubuntu 遇到的一些问题
    win10 如何打开telnet,ftp等服务
    linux集群架构-keepalived高可用
  • 原文地址:https://www.cnblogs.com/phile/p/4473174.html
Copyright © 2011-2022 走看看