1. 程式人生 > >【APIO2014】迴文串 jzoj 3654/洛谷 3649/bzoj 3676 迴文樹(迴文自動機)

【APIO2014】迴文串 jzoj 3654/洛谷 3649/bzoj 3676 迴文樹(迴文自動機)

題目

考慮一個只包含小寫拉丁字母的符串 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; }