题意

https://www.lydsy.com/JudgeOnline/problem.php?id=3676

思路

好像还是回文自动机裸体,但是 \(\text{Manacher}\) +后缀自动机+倍增也可以解决。

首先可以一遍 \(\text{Manacher}\) 得到本质不同的回文串,然后分别求一次出现次数,更新答案。不能发现后缀自动机可以比较轻松的求出一个字串的出现次数,但是需要快速回答。所以需要快速找到一个字串在后缀自动机上的所属节点。

注意到后缀链接连接着一段后缀相等的位置,所以预处理 \([1,i]\) 在后缀自动机的位置,对于一个串 \([s,t]\) ,从 \([1,t]\) 的位置开始跳后缀链接,找到属于 \([s,t]\) 的位置,这里使用倍增跳跃就可以做到一个 \(\log\) 。

有一个细节,空间开不下的话,后缀数组的 \(ch\) 用完了之后可以拿来跳倍增。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
const int N=(int)6e5+5;
template<const int maxn,const int maxm,typename T>struct Linked_list
{
int head[maxn],nxt[maxm],tot;T to[maxm];
Linked_list(){clear();}
T &operator [](const int x){return to[x];}
void clear(){memset(head,-1,sizeof(head)),tot=0;}
void add(int u,T v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N,int>G;
int ch[N][26],slink[N],len[N],sz[N];
int *fa[N];
int las,tot;
char str[N];int idx[N];
char mnc[N];int p[N];
int n;
ll ans; void init()
{
las=tot=1;
FOR(i,0,25)ch[1][i]=0;
len[1]=slink[1]=0;
}
void extend(char c)
{
int p=las,cur=++tot;
FOR(i,0,25)ch[cur][i]=0;
len[cur]=len[p]+1;
sz[cur]=1;
for(;p&&!ch[p][c-'a'];p=slink[p])ch[p][c-'a']=cur;
if(!p)slink[cur]=1;
else
{
int q=ch[p][c-'a'];
if(len[p]+1==len[q])
slink[cur]=q;
else
{
int clone=++tot;
FOR(i,0,25)ch[clone][i]=ch[q][i];
slink[clone]=slink[q];
len[clone]=len[p]+1;
sz[clone]=0;
slink[cur]=slink[q]=clone;
for(;p&&ch[p][c-'a']==q;p=slink[p])ch[p][c-'a']=clone;
}
}
las=cur;
}
void dfs(int u)
{
EOR(i,G,u)
{
int v=G[i];
dfs(v);
sz[u]+=sz[v];
}
} void solve(int l,int r)
{
int p=idx[r];
DOR(i,20,0)if(len[fa[p][i]]>=r-l+1)
p=fa[p][i];
chk_max(ans,1ll*sz[p]*(r-l+1));
} void Manacher(char *str,int len)
{
int n=1;
mnc[1]='#';
FOR(i,1,len)mnc[++n]=str[i],mnc[++n]='#';
int mr=0,pos;
FOR(i,1,n)
{
if(i<=mr)p[i]=std::min(p[(pos<<1)-i],mr-i+1);
else p[i]=1;
while(i-p[i]>=1&&i+p[i]<=n&&mnc[i-p[i]]==mnc[i+p[i]])
{
p[i]++;
if(mnc[i-p[i]+1]=='#')solve((i-p[i]+1+1)>>1,(i+p[i]-1-1)>>1);
}
if(chk_max(mr,i+p[i]-1))pos=i;
}
} int main()
{
scanf("%s",str+1);
n=strlen(str+1);
init();
FOR(i,1,n)extend(str[i]),idx[i]=las;
FOR(i,2,tot)G.add(slink[i],i);
FOR(i,0,tot)fa[i]=ch[i];
FOR(i,1,tot)fa[i][0]=slink[i];
FOR(j,1,20)FOR(i,1,tot)fa[i][j]=fa[fa[i][j-1]][j-1];
dfs(1);
Manacher(str,n);
printf("%lld\n",ans);
return 0;
}

APIO 2014 回文串(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. [APIO2014]回文串 manacher 后缀数组

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

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

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

  6. 解题:APIO 2014 回文串

    题面 初见SAM 洛谷数据太弱了,我SAM写错了居然有90pts=.=??? SAM求一个子串$(l,r)$的出现次数:从右端点对应状态开始在parent树上倍增,当目标节点的$len$大于等于子串长 ...

  7. BZOJ4755 [JSOI2016]扭动的回文串 【后缀数组】【manacher】

    题目分析: 我写了史上最丑的后缀数组,怎么办? 首先manacher一遍两个串,这样只用考虑第三问.用$作为间隔符拼接两个串,把第一个串翻转.枚举回文中心,取最长的回文串,对于剩下的部分利用LCP匹配 ...

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

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

  9. 【回文串-Manacher】

    Manacher算法能够在O(N)的时间复杂度内得到一个字符串以任意位置为中心的回文子串.其算法的基本原理就是利用已知回文串的左半部分来推导右半部分. 转:http://blog.sina.com.c ...

随机推荐

  1. Tkinter 项目-屏保

    参考教程,以及网上资料,针对小白更好理解 关于tkinter的屏保涉及的知识点和思想 项目分析: 屏保启动方式:手动,自动 敲击键盘或者移动鼠标后,或者其他引发事件,则停止 如果屏保是一幅画的话,则没 ...

  2. 2PC/3PC/Paxos

    在分布式系统中,一个事务可能涉及到集群中的多个节点.单个节点很容易知道自己执行的事务成功还是失败,但因为网络不可靠难以了解其它节点的执行状态(可能事务执行成功但网络访问超时). 若部分节点事务执行失败 ...

  3. C#基础加强(9)之对象序列化(二进制)

    介绍 对象序列化是将对象转换为二进制数据(字节流),反序列化是将二进制数据还原成对象.对象的非持久态的,不仅在程序重启.操作系统重启会造成对象的丢失,就是退出函数范围等都可能造成对象的消失,而序列化与 ...

  4. 【Idea】-NO.163.Idea.2 -【How to show the horizontal scroll?】

    Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...

  5. 用HTML5+原生js实现的推箱子游戏

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. Linux定时任务调用sh文件

    1.编写sh文件 创建:vi test.sh 写入:date >> /xiaol/data.txt 2.默认创建的这个sh问件是没有执行权限的,修改权限 chmod 777 test.sh ...

  7. 304. Range Sum Query 2D - Immutable(动态规划)

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  8. CLASS类继承

    单继承:# class People: 经典类class People(object): #新式类 def __init__(self,name,age,n=1000): self.name = na ...

  9. JAVA函数的重载和重写

    一.什么是重载(overlording) 在JAVA中,可以在同一个类中存在多个函数,函数名称相同但参数列表不同.这就是函数的重载(overlording).这是类的多太性表现之一. 二.重载的作用: ...

  10. GRU and LSTM

    门控循环单元(GRU): 背景: 当时间步数较大或者时间步数较小的时候,循环神经网络的梯度较容易出现衰减或者爆炸.虽然裁剪梯度可以应对梯度爆炸, 但是无法解决梯度衰减的问题.正因为如此,循环神经网络在 ...