【洛谷P4555】最長雙回文串
阿新 • • 發佈:2019-04-29
namespace n+1 const 枚舉 its 定義 struct 延伸 i++
題目大意:給定一個長度為 N 的字符串 S,求 S 的最長雙回文子串的長度,雙回文子串定義為是 S 的一個子串,可以分成兩個互不相交的回文子串。
題解:利用回文自動機 len 數組的性質,即:len 數組記錄的是以每個點 i 字符結尾的,向左可以延伸的,最長回文串的長度。正向遍歷一遍串 S,統計出對於每個點向左可以延伸的最長回文長度,再將字符串翻轉,統計出向右可以延伸的長度。最後枚舉間斷點,統計答案即可。
註:增量法回文自動機的插入依賴於字符串下標遞增的順序,因此倒序插入必須將原串轉置。
代碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; char s[maxn]; int n,ans,l[maxn],r[maxn]; struct PAM{ int tot,last,trie[maxn][26],len[maxn],fail[maxn]; PAM(){tot=1,fail[0]=fail[1]=1,len[1]=-1;} int insert(int c,int i){ int p=last; while(s[i-len[p]-1]!=s[i])p=fail[p]; if(!trie[p][c]){ int now=++tot,k=fail[p]; while(s[i-len[k]-1]!=s[i])k=fail[k]; len[now]=len[p]+2,fail[now]=trie[k][c]; trie[p][c]=now; } last=trie[p][c]; return len[last]; } }pam_l,pam_r; int main(){ scanf("%s",s+1),n=strlen(s+1); for(int i=1;i<=n;i++)l[i]=pam_l.insert(s[i]-'a',i); reverse(s+1,s+n+1); for(int i=1;i<=n;i++)r[n-i+1]=pam_r.insert(s[i]-'a',i); for(int i=1;i<n;i++)ans=max(ans,l[i]+r[i+1]); printf("%d\n",ans); return 0; }
【洛谷P4555】最長雙回文串