HYSBZ 2565 Manacher算法

来源:互联网 发布:日期倒计时软件 编辑:程序博客网 时间:2024/06/04 20:45

题意

中文题,不解释

题解

这道题正解应该是回文树,不过用Manacher算法8s水过了。首先用Manacher算法算出来P数组,然后将所有的P数组-1,这样的话便能得到以某一个位置为中心的回文串最长长度。然后我们可以根据这个长度为两个端点赋值。dp1[i]代表从i-1开始向前的最长回文子串,dp2[i]代表从i+1开始最长回文子串。我们可以在i这个位置,得到(dp2[i-p[j]],dp1[i+p[j]])。最后我们可以从1开始遍历,寻找在哪个位置前后回文子串组成的子串长度最长。(当然,有人可能会疑惑这样搞会不会产生一些问题,因为我们可以发现这样组成的串是不包含I的。如果仔细想一下就会发现,这样是没有任何问题的。因为题目要求最长子串,所以最长子串一定是在’#’处得到,不会产生任何问题)

代码

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<string>#include<set>#include<map>#include<bitset>#include<stack>#include<string>#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(a) while(a)#define MEM(a,b) memset(a,b,sizeof(a))#define LL long long#define INF 0x3f3f3f3f3f3f3f3f#define MAXN 120050#define MOD 1000000007#define EPS 1e-3using namespace std;char s[120010],ts[220010];int p[220010];int dp1[220010],dp2[220010];void solve() {    MEM(p,0);    MEM(dp1,0);    MEM(dp2,0);    int n=strlen(s);    int pos=0;    ts[pos++]='$';    ts[pos++]='#';    UP(i,0,n) {        ts[pos++]=s[i];        ts[pos++]='#';    }    ts[pos]='\0';    int mx=0,id;    UP(i,1,pos) {        if(mx>i) p[i]=min(p[id*2-i],mx-i);        else p[i]=1;        W(ts[i+p[i]]==ts[i-p[i]]) p[i]++;        if(i+p[i]>mx) {            mx=i+p[i];            id=i;        }    }    UP(i,1,pos) p[i]--;    UP(i,1,pos){        DOWN(j,p[i]+1,1){            if(i+j>=pos) continue;            if(dp1[i+j]>=j) break;            dp1[i+j]=j;        }        DOWN(j,p[i]+1,1){            if(i-j<=0) continue;            if(dp2[i-j]>=j) break;            dp2[i-j]=j;        }    }    int ans=-INF;    UP(i,1,pos){        if(dp1[i]&&dp2[i]) ans=max(ans,dp1[i]+dp2[i]);//        cout<<i<<" "<<dp1[i]<<" "<<dp2[i]<<endl;    }    printf("%d\n",ans);}int main() {    W(~scanf("%s",s)) {        solve();    }}
原创粉丝点击