bzoj 2342 [Shoi2011]双倍回文(manacher,set)

时间:2023-03-08 17:24:41

【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=2342

【题意】

求出形如w wR w wR的最长连续子串。

【思路】

用manacher算法计算出p[],表示以i与i+1为中心的最长回文字串长度/2

枚举第一个wR的结束位置x,当且仅当y-p[y]<=x且y<=x+p[x]/2子串[x+1,y]是一个答案,更新ans。

满足的条件是一个二维偏序,按照y-p[y]排序,在查询x之前保证将所有满足第一个式子的x'加入set,查询时找到x+p[x]/2在set中的前驱即为最大的答案。

【代码】

 #include<set>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 5e5+; set<int> t;
set<int> ::iterator it; char s[N];
int n,ans,p[N],q[N]; bool cmp(int a,int b)
{
return (a-p[a])<(b-p[b]);
} void manacher()
{
int mx=,id;
for(int i=;i<=n;i++)
{
if(mx>=i)p[i]=min(mx-i,p[*id-i]);
else
p[i]=;
while(s[i+p[i]+]==s[i-p[i]]) p[i]++;
if(p[i]+i>mx)id=i,mx=p[i]+i;
}
} int main()
{
scanf("%d%s",&n,s+);
s[]='#';
manacher();
for(int i=;i<=n;i++) q[i]=i;
sort(q+,q+n+,cmp);
int now=;
for(int i=;i<=n;i++)
{
while(now<=n&&q[now]-p[q[now]]<=i)
t.insert(q[now++]);
it=t.upper_bound(i+p[i]/);
if(it!=t.begin())
ans=max(ans,(*--it-i)*);
}
printf("%d\n",ans);
return ;
}

P.S. 新姿势[马拉车]解锁 :)