您的位置:首页 > 其它

bzoj2342 [Shoi2011]双倍回文

2017-06-16 19:05 288 查看
传送门

参考题解

一道很好的manacher练手题。。

一开始把题读错了,以为是w1w′1w2w′2形式的就可以,题目哪有这么简单

观察题目,我们可以发现:对于每一个符合条件的子串,都有j+p[j]>=i , j < i,p[j]是以j为中心最大的

画个图可能更好理解



图中绿色矩形中就是一种可行方案。

所以manacher计算以每个字符为中心的回文半径,然后枚举i和j

//据说时限10s暴力能跑过,然而并没有意义

我们可以用并查集维护当前可行的j,每次往后跳find(j),直到符合要求或者没有可行方案

原理:如果某一个j已经无法覆盖当前的i,那么对于后面的i来说这个j也毫无意义

这样时间复杂度就非常优美了

CODE:

#include<cstdio>
char a[1000010];
int p[1000010];
int f[1000010];
int n,len,ans,pos,mx;
inline int max(const int &a,const int &b){return a>b?a:b;}
inline int min(const int &a,const int &b){return a<b?a:b;}
int find(int n)
{
if(f
!=n) f
=find(f
);
return f
;
}
int main()
{
scanf("%d\n",&n);
a[0]='$';
for(int i=1;i<=n;i++)
a[++len]='#',a[++len]=getchar();
a[len+1]=a[len+2]='#';
for(int i=1;i<=len;i++)
{
if(i<mx) p[i]=min(p[pos*2-i],mx-i);
else p[i]=1;
while(a[i-p[i]]==a[i+p[i]]) p[i]++;
if(i+p[i]>mx) mx=i+p[i],pos=i;
}
for(int i=1;i<=len;i++)
if(a[i]=='#') f[i]=i;
else f[i]=i+1;
for(int i=3;i<=len;i+=2)
{
int tmp=i-(p[i]>>1);
if(!tmp) continue;
tmp=find(tmp);
while(tmp+p[tmp]<i&&tmp<i) f[tmp]=find(tmp+1),tmp=f[tmp];
if(tmp<i) ans=max(ans,(i-tmp)<<1);
}
printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息