传送门
这题似乎用manacher可做而且很快,但用PAM做可能更好理解.
看了题解都是用fail指针来写这题,但其实可以不用那么麻烦.
考虑一下双倍回文的性质.
1.首先肯定是一个回文字符串.
2.从中间分开两边都是回文串.
3.长度是4的倍数.
暴力:第一个性质保证了它一定在PAM的一个节点上,我们可以最暴力的对每个节点判断是否是双倍回文.这种做法就不提了.
正解:双倍回文串在PAM上的特点是它的转移字符形成的字符串一定是回文串.比如说abbaabba. 在PAM上它是这么形成的:a->b->b->a.可以发现这个转移字符形成的字符串同样是回文的.所以我们根据这个特点来判断就ok了.可以再套一个PAM或者直接用manacher判断.
注意不能对每个节点都判断一次,而是在每个叶子节点跑一遍PAM或者manacher判断最长的回文串就好了.这回文串一定要是1-i形成的回文串.
PS:这个代码虽然又长又慢,但是思路应该是很清晰的.
代码:
#define LL long long
#define pq priority_queue
#define ULL unsigned long long
#define pb push_back
#define mem(a,x) memset(a,x,sizeof a)
#define pii pair<int,int>
#define fir(i,a,b) for(int i=a;i<=(int)b;++i)
#define afir(i,a,b) for(int i=(int)a;i>=b;--i)
#define ft first
#define vi vector<int>
#define sd second
#define ALL(a) a.begin(),a.end()
#define bug puts("-------")
#define mpr(a,b) make_pair(a,b)
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
inline int read(){
int x = 0,f=1;char ch = getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){
x=x*10+ch-'0';ch=getchar();}
return x*f;
}
namespace man{
int p[N*3],n;
void getstr(string str,int &ans){
n = str.size();
string newstr = "";
newstr += "&";newstr += "#";
for(auto x:str) newstr += x,newstr += "#";
newstr += "*";
str = newstr;
int id = 0,mx = 0;
fir(i,0,(int)str.size()-2)
p[i] = 0;
fir(i,1,(int)str.size()-2){
if(i < mx) p[i] = min(p[2*id-i],mx-i);
else p[i] = 1;
while(str[i-p[i]] == str[i+p[i]]) p[i]++;
if(i + p[i] > mx) id = i,mx = i+p[i];
int pos = i/2;
if((p[i]-1)*2%4==0 && (pos*2 == p[i]-1)) ans = max(ans,(p[i]-1)*2);
}
}
}
namespace PAM{
// 双倍回文条件 : 1.在PAM上面的路径字符串是回文的 2.路径长度*2 % 4 == 0
int nxt[26][N],S[N],fail[N],num[N],last,n,tot,ans;
int cnt[N],len[N];
int newnode(int l){
len[tot] = l,cnt[tot] = num[tot] = 0;fir(i,0,25) nxt[i][tot] = 0;return tot++;
}
void init(){
last = n = tot = 0;newnode(0),newnode(-1);fail[0] = 1;S[0] = -1;
}
int getfail(int x){
while(S[n-len[x]-1] != S[n])
x = fail[x];
return x;
}
void add(int ch){
ch -= 'a';
S[++n] = ch;
int cur = getfail(last);
if(!nxt[ch][cur]){
int now = newnode(len[cur]+2);
fail[now] = nxt[ch][getfail(fail[cur])];
nxt[ch][cur] = now;
num[now] = num[fail[now]] + 1;
}
last = nxt[ch][cur];
cnt[last]++;
}
string s = "";
void dfs(int p){
bool f = 1;
int siz = s.size();
fir(i,0,25){
if(nxt[i][p]){
s += ('a'+i);
dfs(nxt[i][p]);
f = 0;
s.resize(siz);
}
}
if(f){
man::getstr(s,ans);
}
}
}
int main(){
int n;
string s;
cin >> n >> s;
PAM::init();
for(auto x:s) PAM::add(x);
PAM::dfs(0);
cout << PAM::ans << "\n";
return 0;
}
/* 1
aaaaaabcddcbaabcddcbaaaaaa
16
*/