【APIO2014】迴文串 jzoj 3654/洛谷 3649/bzoj 3676 迴文樹(迴文自動機)
阿新 • • 發佈:2019-01-10
題目
考慮一個只包含小寫拉丁字母的符串 s。我們定義 s的一個子串 t的“出現值”為 t在 s中的出現次數乘以t的長度。 請你求出s的所有迴文子串中的最大出現值。
分析
迴文樹(迴文自動機)模板題
迴文樹連結———連結
還有後綴自動機的寫法,但是我太弱了…不會
ps:迴文樹雖然應用比較少,但是程式碼短,好理解,解決特定問題有奇效.
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#define maxn 500005
#define maxm 600005
#define INF 0x7fffffff;
using namespace std;
int next[maxn][30],fail[maxn],len[maxn];
long long cnt[maxn];
int S[maxn];
int last;
int N=0;
int p=0;
void newnode(int l)
{
++p;
for (int i=1;i<=26;i++) next[p][i]=0;
len[p]=l;
cnt[p]=0;
}
int get_fail(int x)
{
while (S[N-len[x]-1]!=S[N]) x=fail[x];
return x;
}
void add(char C)
{
int c=C-'a'+1;
S[++N]=c;
int cur=get_fail(last);
if (!next[cur][c])
{
newnode(len[cur]+2);
fail[p]=next[get_fail(fail[cur])][c];
next[cur][c]=p;
}
last=next[cur][c];
cnt[last]++;
}
void count()
{
for (int i=p;i>=0;i--) cnt[fail[i]]+=cnt[i] ;
}
int main()
{
freopen("palindrome.in","r",stdin);
freopen("palindrome.out","w",stdout);
string s;
cin>>s;
p=-1;
newnode(0);
newnode(-1);
last=0; N=0;
S[N]=-1; fail[0]=1;
for (int i=0;i<s.length();i++)
{
add(s[i]);
}
count();
long long ans=0;
for (int i=2;i<=p;i++)
{
long long k=cnt[i]*len[i];
if (k>ans) ans=k;
}
cout<<ans;
}