1. 程式人生 > >【洛谷P4555】最長雙回文串

【洛谷P4555】最長雙回文串

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】最長雙回文串