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数组表示该节点代表的 ...
随机推荐
- redis之字符串命令源代码解析(二)
形象化设计模式实战 HELLO!架构 redis命令源代码解析 在redis之字符串命令源代码解析(一)中讲了get的简单实现,并没有对 ...
- 【LeetCode-面试算法经典-Java实现】【063-Unique Paths II(唯一路径问题II)】
[063-Unique Paths II(唯一路径问题II)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Follow up for "Unique Pa ...
- Java中二进制字节与十六进制互转
在Java中字节与十六进制的相互转换主要思想有两点: 1.二进制字节转十六进制时,将字节高位与0xF0做"&"操作,然后再左移4位,得到字节高位的十六进制A;将字节低位与0 ...
- Linux系统的LOG日志文件及入侵后日志的清除
UNIX网管员主要是靠系统的LOG,来获得入侵的痕迹.当然也有第三方工具记录入侵系统的 痕迹,UNIX系统存放LOG文件,普通位置如下: /usr/adm - 早期版本的UNIX/var/adm - ...
- apache-maven-3.0.4-bin.zip
http://zhidao.baidu.com/share/2a8974fd1546ef5f11ad9cccb3cabf88.html apache-maven-3.0.4-bin.zip
- vue-router学习例子分享
http://blog.csdn.net/bboyjoe/article/details/52804988 <!DOCTYPE html> <html lang="en&q ...
- CSS3侧滑导航
<!DOCTYPE> <html> <head> <meta charset="utf-8" /> <meta name=&q ...
- 联想杨天 S4130-12 win10改win7 bios参数设置
一.进入bios 开机后按 F1 二.改bion参数 1.移动到 save& Exit ,修改 OS optimized defaults 为“Disbled” 再 “F9” 保存 2. ...
- 休假结束,Linus重回内核开发岗位
在休假反省一个多月之后,Linus Torvalds 又回来了.10 月 22 日爱丁堡举行的欧洲开源峰会上,Linus Torvalds 将与内核维护者们碰头,这是他重新接管Linux内核开发的第一 ...
- 紫书 例题 9-14 UVa 1218 (树形dp)
这道题有个初始值设成1e9, 然后这个值是要加很多次的,然后就会溢出变成负数, 然后就一直WA, 找这个bug找了一个小时--以后不能随便这样设那么大, 要考虑会不会加很多次然后溢出. 讲一下思路. ...