P4287 [SHOI2011] 双倍回文
题意
给定字符串 \(s\),求其长度最大的子串 \(t\),使得 \(t\) 可以看做由字符串 \(w\) 按照 \(ww^Rww^R\) 的顺序拼接而成,其中 \(w^R\) 代表 \(w\) 翻转后的结果。
\(|s|\le 5\times10^5\)
分析
一个直观的想法是枚举第二个(最中间的)分界线 \(i\) 和第三个分界线 \(j\),设 \(d_i\) 是以分界线 \(i\) 为回文中心的最长回文半径,则判定成功的条件是 \(d_i\ge 2(j-i),d_j\ge j-i\),移项使得两边只与其中一个有关:\(d_i+2i\ge 2j,i\ge j-d_j\),不妨枚举 \(j\),我们要找的就是满足这些条件的最小的 \(i\),虽然可以三维偏序,但这太不优美了。考虑到 \(2j\) 单调递增,那么随着 \(j\) 增长有些 \(i\) 将不再合法,并且在之后的时刻都不会合法,用 set 维护可能有效的 \(i\),对于限制 2,相当于 \(i\) 要大于等于某个定值,直接 set 上 lower_bound 即可。
时间复杂度 \(O(n\log n)\)。
int n;
char s[maxn],t[maxn];
int d[maxn];
void manacher(){
t[0]='!';
rep(i,1,n)t[2*i-1]='#',t[2*i]=s[i];
t[2*n+1]='#',t[2*n+2]='@';
d[1]=0;
int mid=1,r=1;
rep(i,2,2*n){
int p=i>r?0:min(d[2*mid-i],r-i);
while(t[i-p-1]==t[i+p+1])++p;
d[i]=p;
if(i+p>r)r=i+p,mid=i;
}
}
inline void solve_the_problem(){
n=rd(),scanf("%s",s+1);
manacher();
set<int>ss;
priority_queue<pii,vector<pii>,greater<pii>>q;
int ans=0;
rep(i,1,n){
while(!q.empty()&&q.top().fi<2*i)ss.erase(q.top().se),q.pop();
auto it=ss.lower_bound(i-d[2*i-1]/2);
if(it!=ss.end())ckmx(ans,4*(i-*it));
ss.insert(i),q.push(mp(2*i+d[2*i-1]/2,i));
}
write(ans);
}

浙公网安备 33010602011771号