您的位置:首页 > 其它

回文自动机 模板 bzoj3676【Apio2014】回文串

2017-04-12 19:13 387 查看
题目描述:

考虑一个只包含小写拉丁字母的字符串s。

我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。

题目分析:(回文自动机)

某只问:回文自动机有什么用?

另只答:除了把Apio2014回文串那题变成裸题之外没什么卵用了。

……

本蒟蒻:嗯嗯(无脑点头)

回文自动机可以识别一个串的所有回文子串【的一半】。

像Manacher一样在两个字符中间插入一个‘ ` ’,这样可以只写一个根。

具体的做法就是找到上一个字符为结尾且把当前要插入的字符插入之后仍然是回文串的最长回文串,然后顺理成章的接在后面接好啦。

哎,说起来简单=。=

代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define N 310000
using namespace std;
inline long long Max(long long x,long long y) { return x>y?x:y; }
int n;
long long ans;
char s[N<<1];
namespace Palindrome_Automaton{
struct Trie{
Trie *son[27],*fail;
int dpt,cnt;
Trie() {}
Trie(int _):dpt(_){}
}mempool[N<<1],*C=mempool;
Trie *root=new (C++) Trie(0),*last=root;
void extend(int x)
{
Trie *p=last;
while(s[x-2*p->dpt]!=s[x])
p=p->fail;
if(p->son[s[x]-'`'])
last=p->son[s[x]-'`'];
else
{
last=p->son[s[x]-'`']=new (C++) Trie(p->dpt+1);
for(p=p->fail;p;p=p->fail)
if(s[x-2*p->dpt]==s[x])
{
last->fail=p->son[s[x]-'`'];
break;
}
if(!p) last->fail=root;
}
last->cnt++;
}
}
void bfs()
{
using namespace Palindrome_Automaton;
static Trie *q[N<<1];
int i,l=1,r=0;
q[++r]=root;
while(l<=r)
{
Trie *p=q[l++];
for(int i=0;i<=26;i++)
if(p->son[i])
q[++r]=p->son[i];
}
for(i=r;i>1;i--)
{
Trie *p=q[i];
p->fail->cnt+=p->cnt;
ans=Max(ans,(long long)(p->dpt-1)*p->cnt);
}
}
int main()
{
using namespace Palindrome_Automaton;
scanf("%s",s+1);
n=strlen(s+1);
for(int i=n<<1|1;i;i--)
{
if(i&1) s[i]='`';
else s[i]=s[i>>1];
}
for(int i=1;i<=(n<<1|1);i++)
extend(i);
bfs();
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: