BZOJ3676: [Apio2014]回文串(SAM+Manacher/PAM)
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
abacaba
【样例输入2]
www
Sample Output
7
【样例输出2]
4
解题思路:
1.Manacher+SAM
首先,是不是有人告诉过你本质不同的回文串有O(n)个,就是在Manacher中学过的。
每次在Manacher扩展f[i]时将其在SAM的Parent树中匹配,就是len*wgt最大值。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long lnt;
const int N=;
const int M=;
struct sant{
int tranc[];
int len;
int pre;
}s[N];
struct pnt{
int hd;
int fa[];
int wgt;
}p[N];
int cnt;
int dfn;
int siz;
int fin;
int len,m;
lnt ans;
char tmp[M];
int str[M<<];
int f[N];
int pos[M<<];
int endpos[M];
int has[N];
int topo[N];
void Insert(int c)
{
int nwp,nwq,lsp,lsq;
nwp=++siz;
p[nwp].wgt=;
s[nwp].len=s[fin].len+;
for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
s[lsp].tranc[c]=nwp;
if(!lsp)
s[nwp].pre=;
else{
lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+)
s[nwp].pre=lsq;
else{
nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+;
s[nwp].pre=s[lsq].pre=nwq;
while(s[lsp].tranc[c]==lsq)
{
s[lsp].tranc[c]=nwq;
lsp=s[lsp].pre;
}
}
}
fin=nwp;
return ;
}
int check(int l,int r)
{
if(l<||r>len)
return ;
int root=endpos[r];
for(int i=;i>=;i--)
{
if(s[p[root].fa[i]].len>=r-l+)
root=p[root].fa[i];
}
ans=std::max(ans,(lnt)(r-l+)*(lnt)(p[root].wgt));
return (r-l+)*p[root].wgt;
}
int main()
{
scanf("%s",tmp+);
fin=++siz;
len=strlen(tmp+);
for(int i=;i<=len;i++)
{
Insert(tmp[i]-'a');
endpos[i]=fin;
}
for(int i=;i<=siz;i++)
has[s[i].len]++;
for(int i=;i<=siz;i++)
has[i]+=has[i-];
for(int i=;i<=siz;i++)
topo[has[s[i].len]--]=i;
for(int i=siz;i;i--)
{
int x=topo[i];
p[s[x].pre].wgt+=p[x].wgt;
}
for(int i=;i<=siz;i++)
{
int x=topo[i];
p[x].fa[]=s[x].pre;
p[].fa[]=;
for(int j=;j<=;j++)
p[x].fa[j]=p[p[x].fa[j-]].fa[j-];
}
int tmpl=;
str[++tmpl]='*';
for(int i=;i<=len;i++)
{
str[++tmpl]='#';
str[++tmpl]=tmp[i];
pos[tmpl]=i;
}
str[++tmpl]='#';
str[++tmpl]='$';
int now=;
for(int i=;i<=tmpl;i++)
{
f[i]=std::min(f[now]+now-i,f[now*-i]);
f[i]=std::max(f[i],);
check(pos[i-f[i]+],pos[i+f[i]-]);
while(str[i-f[i]]==str[i+f[i]])
{
f[i]++;
check(pos[i-f[i]+],pos[i+f[i]-]);
}
if(f[now]+now<f[i]+i)
now=i;
}
printf("%lld\n",ans);
return ;
}
2.PAM模板
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long lnt;
struct pant{
int tranc[];
int pre;
int len;
int wgt;
};
namespace PAM{
pant h[];
int siz;
int fin;
void Res(void)
{
fin=;
siz=;
h[].pre=h[].pre=;
h[].len=-;
return ;
}
bool mismatch(char *a,int i,int pa)
{
return a[i-h[pa].len-]!=a[i];
}
void Insert(char *a,int i)
{
int nwp,lsp,mac;
lsp=fin;
int c=a[i]-'a';
while(mismatch(a,i,lsp))
lsp=h[lsp].pre;
if(!h[lsp].tranc[c])
{
nwp=++siz;
mac=h[lsp].pre;
h[nwp].len=h[lsp].len+;
while(mismatch(a,i,mac))
mac=h[mac].pre;
h[nwp].pre=h[mac].tranc[c];
h[lsp].tranc[c]=nwp;
}
fin=h[lsp].tranc[c];
h[fin].wgt++;
return ;
}
lnt build(void)
{
lnt ans=;
for(int i=siz;i;i--)
{
h[h[i].pre].wgt+=h[i].wgt;
ans=std::max(ans,(lnt)(h[i].len)*(lnt)(h[i].wgt));
}
return ans;
}
}
char tmp[];
int main()
{
PAM::Res();
scanf("%s",tmp+);
int len=strlen(tmp+);
for(int i=;i<=len;i++)
PAM::Insert(tmp,i);
printf("%lld\n",PAM::build());
return ;
}
BZOJ3676: [Apio2014]回文串(SAM+Manacher/PAM)的更多相关文章
- BZOJ3676:[APIO2014]回文串(SAM,Manacher)
Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行 ...
- BZOJ3676 APIO2014回文串(manacher+后缀自动机)
由于本质不同的回文子串数量是O(n)的,考虑在对于每个回文子串在第一次找到它时对其暴力统计.可以发现manacher时若右端点移动则找到了一个新回文串.注意这样会漏掉串长为1的情况,特判一下. 现在问 ...
- bzoj3676 [Apio2014]回文串 卡常+SAM+树上倍增
bzoj3676 [Apio2014]回文串 SAM+树上倍增 链接 bzoj luogu 思路 根据manacher可以知道,每次暴力扩展才有可能出现新的回文串. 所以推出本质不同的回文串个数是O( ...
- [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串
回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...
- [BZOJ3676][APIO2014]回文串(Manacher+SAM)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3097 Solved: 1408[Submit][Statu ...
- [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3396 Solved: 1568[Submit][Statu ...
- [bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增
Brief Description 一个回文串的value定义为这个回文串的长度乘以出现次数.给定一个字符串,求\(value_{max}\). Algorithm Design 我们使用Manach ...
- BZOJ3676 APIO2014 回文串 Manacher、SA
传送门 首先一个结论:串\(S\)中本质不同的回文串个数最多有\(|S|\)个 证明考虑以点\(i\)结尾的所有回文串,假设为\(S[l_1,i],S[l_2,i],...,S[l_k,i]\),其中 ...
- bzoj3676: [Apio2014]回文串 pam
题意:字符串s.我们定义s的一个子串t的"出 现值"为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. 题解:pam板子题 //cnt数组表示该节点代表的 ...
随机推荐
- POJ 1152 An Easy Problem! (取模运算性质)
题目链接:POJ 1152 An Easy Problem! 题意:求一个N进制的数R.保证R能被(N-1)整除时最小的N. 第一反应是暴力.N的大小0到62.发现当中将N进制话成10进制时,数据会溢 ...
- Linux能ping通IP,ping不通域名
今天碰到个问题, 能ping通IP地址, ping不通域名, 一直以为是 DNS解析服务器的问题, 找了半天. 问题不在这里. [root@www postfix]# cat /etc/resolv. ...
- 在Linux终端使用W3M浏览器下载文件
在Linux终端使用W3M浏览器下载文件 W3M 是3个基于Linux系统命令行的WEB网站浏览工具(w3m/Links/Lynx) 对于需要验证cookie 和来源的页面,比如163的超大附件,直接 ...
- java关于File.separator
写好代码在模拟环境下测试,完全没问 题:但linux+tomcat下用的时候,却老是报告“No such file or diretory ”的异常,上传不了.后来发现是文件路径的问题.我的模拟测试环 ...
- javaScript 三目运算符初探
三目运算符 三目运算符,又称条件运算符,是计算机语言的重要组成部分.它是唯一有3个操作数的运算符,所以有时又称为三元运算符.一般来说,三目运算符的结合性是右结合的. 定义 对于条件表达式b ? x : ...
- 【CS Round #37 (Div. 2 only) D】Reconstruct Graph
[Link]:https://csacademy.com/contest/round-37/task/reconstruct-graph/statement/ [Description] 给你一张图; ...
- xwiki操作手册
Xwiki官网:http://www.xwikichina.com/xwiki/bin/view/Main/中文官网. 1 用户管理 1.1 添加新用户 用户管理需要管理员权限,管理员登陆后 ...
- qt程序实现打开文件夹
QString path=QDir::currentPath();//获取程序当前目录 path.replace("/","\\");//将地址中的" ...
- VC、IE、ASP环境下打印、预备的完美解决方式
一种基于XML的报表开发工具,它支持从设计报表.调用API打印.预览,能支持分布式报表.方便报表的存储.转发. 在报表中能嵌入VBScript,能方便地訪问VB,VC的变量,能訪问COM组件.ADO等 ...
- 【Android界面实现】使用GestureOverlayView控件实现手势识别
在Android开发中,我们不光能够使用已有的实现方式.并且,我们还能够利用Android这个智能手机平台.实现一些比較有特色的功能. 本篇文章介绍使用GestureOverlayView这个控件.实 ...