由于本质不同的回文子串数量是O(n)的,考虑在对于每个回文子串在第一次找到它时对其暴力统计。可以发现manacher时若右端点移动则找到了一个新回文串。注意这样会漏掉串长为1的情况,特判一下。

  现在问题变为统计一个子串的出现次数。可以用SA,二分乱搞一下即可。这里使用SAM。以parent树上表示该子串的节点为起点,用倍增往上跳,找到深度最小的满足len限制的点就好了,出现次数就是其right集合的大小。

  uojAC,luoguRE一个点,bzojMLE……

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    ,f=;char c=getchar();
    ;c=getchar();}
    )+(x<<)+(c^),c=getchar();
    return x*f;
}
#define N 600010
],size[N],pos[N>>],p[N];
;
char s[N];
namespace tree
{
    ,fa[N][];
    struct data{int to,nxt;
    }edge[N];
    void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void dfs(int k)
    {
        for (int i=p[k];i;i=edge[i].nxt)
        {
            fa[edge[i].to][]=k;
            dfs(edge[i].to);
            size[k]+=size[edge[i].to];
        }
    }
    void build()
    {
        ;i<=cnt;i++) addedge(fail[i],i);
        fa[][]=;dfs();
        ;j<;j++)
            ;i<=cnt;i++)
            fa[i][j]=fa[fa[i][j-]][j-];
    }
    int calc(int l,int r)
    {
        int x=pos[r];
        ;~j;j--) ) x=fa[x][j];
        return size[x];
    }
}
using tree::calc;
void ins(int c,int n)
{
    ;pos[n]=x;
    while (!son[p][c]&&p) son[p][c]=x,p=fail[p];
    ;
    else
    {
        int q=son[p][c];
        ==len[q]) fail[x]=q;
        else
        {
            ;
            memcpy(son[y],son[q],sizeof(son[q]));
            fail[y]=fail[q];fail[q]=fail[x]=y;
            while (son[p][c]==q) son[p][c]=y,p=fail[p];
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj3676.in","r",stdin);
    freopen("bzoj3676.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    last=cnt=;
    scanf();n=strlen(s+);
    ;i<=n;i++) ins(s[i]-,i);
    tree::build();
    ;i--) s[i*-]=s[i];
    ;i<n;i++) s[i<<]='$';
    ;
    ;i<=n;i++) ans=max(ans,1ll*calc(i,i));
    ;i<n*;i++)
    {
        if (x+p[x]>i) p[i]=min(x+p[x]-i,p[x-(i-x)]);
        >=&&i+p[i]+<n*&&s[i+p[i]+]==s[i-p[i]-])
        {
            p[i]++;
            )-(i-p[i]>>)+)*calc((i-p[i]>>)+,(i+p[i]>>)+));
        }
        if (i+p[i]>x+p[x]) x=i;
    }
    cout<<ans;
    ;
}

BZOJ3676 APIO2014回文串(manacher+后缀自动机)的更多相关文章

  1. [bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增

    Brief Description 一个回文串的value定义为这个回文串的长度乘以出现次数.给定一个字符串,求\(value_{max}\). Algorithm Design 我们使用Manach ...

  2. [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3396  Solved: 1568[Submit][Statu ...

  3. 2018.12.15 bzoj3676: [Apio2014]回文串(后缀自动机)

    传送门 对原串建立一个后缀自动机,然后用反串在上面匹配. 如果当前匹配的区间[l,r][l,r][l,r]包裹了当前状态的endposendposendpos中的最大值,那么[l,maxpos][l, ...

  4. [BZOJ3676][APIO2014]回文串(Manacher+SAM)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3097  Solved: 1408[Submit][Statu ...

  5. BZOJ3676 APIO2014 回文串 Manacher、SA

    传送门 首先一个结论:串\(S\)中本质不同的回文串个数最多有\(|S|\)个 证明考虑以点\(i\)结尾的所有回文串,假设为\(S[l_1,i],S[l_2,i],...,S[l_k,i]\),其中 ...

  6. [APIO2014]回文串 manacher 后缀数组

    题面:洛谷 题解: 还是这个性质:对于每个串而言,本质不同的回文串最多只有O(n)个. 所以我们先求出这O(n)个本质不同的回文串,然后对整个串求一次sa. 然后对于每个回文串,求出它的出现次数,更新 ...

  7. bzoj 3676: [Apio2014]回文串【后缀自动机+manacher】

    用manacher找出本质不同的回文子串放在SAM上跑 #include<iostream> #include<cstdio> #include<cstring> ...

  8. [模板] 回文树/回文自动机 &amp;&amp; BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  9. bzoj3676 [Apio2014]回文串 卡常+SAM+树上倍增

    bzoj3676 [Apio2014]回文串 SAM+树上倍增 链接 bzoj luogu 思路 根据manacher可以知道,每次暴力扩展才有可能出现新的回文串. 所以推出本质不同的回文串个数是O( ...

随机推荐

  1. 创建PO

    FORM FRM_CREATE_PO USING P_POSNR CHANGING P_EBELN. DATA: LV_VENDOR TYPE LIFNR, LV_ITEM TYPE EBELP, L ...

  2. scala学习笔记:理解类继承

    scala> import scala.reflect._ import scala.reflect._ scala> class Person(@BeanProperty var nam ...

  3. PHP 注意问题

    一.表单  1,上传文件的表单使用post方式:还要加上enctype='multipart/form-data'.     2,一般要加上隐藏域:<input type=hidden name ...

  4. Majority Element 解答

    Solution 1 Naive way First, sort the array using Arrays.sort in Java. Than, scan once to find the ma ...

  5. 读书笔记 effective c++ Item 50 了解何时替换new和delete 是有意义的

    1. 自定义new和delete的三个常见原因 我们先回顾一下基本原理.为什么人们一开始就想去替换编译器提供的operator new和operator delete版本?有三个最常见的原因: 为了检 ...

  6. Ext JS 6正式版的GPL版本下载地址

    下面是Ext JS 6正式版的GPL版本下载地址 https://www.sencha.com/legal/gpl/

  7. 总结-Linux

    linux基本操作 系统设置 创建用户 useradd -d /home/liaolongjun -m liaolongjun 设置密码 passwd liaolongjun 查看主机名 uname ...

  8. Kali学习笔记11:僵尸扫描案例

    什么是僵尸扫描?本质也是端口扫描,不过是一种极其隐蔽的扫描方式 所以几乎不会被发现,不过也有着很大缺陷:扫描条件很高 首先需要有一台僵尸机,这里我找好一台win10僵尸机器,IP地址为:10.14.4 ...

  9. HTML基础教程

    <!DOCTYPE html><html> <head> <title></title> </head> <body> ...

  10. Python基础的练习

    ---恢复内容开始--- 简单输入输出交互. >>> name='Jame' >>> print('Hi,%s.'%name) Hi,Jame. >>& ...