题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5371
题目大意:给一串数字,在子串中找到“1-2-1”的形式,其中1和2 是回文串,找出最长的那一串。
思路:利用manacher算法得出最长序列。观察子串形式,1和2是回文串,其实2和后面那个1也是回文串。
在之前我们已经通过manacher算法得到了每个数字所能延伸的长度,所以我们只要枚举第二段到第三段的距离即可。
当遇到第i个数字时,那么第二段和第三段的距离就是i+p[i],令j=i+p[i]-1,那么对于j这个位置就有p[j],我们只要j-(p[j]-1) <= i 就可以了。
这里的意思就是:j的回文半径大于i的回文半径,这样就能保证第二段和第三段也是回文串了。
注意有个优化:如果j-i<max,那么久不需要去看了。
#include<stdio.h> #include<string.h> #define min(a,b) a<b?a:b int str[220005],s[220005]; int len,p[220005],a[22005]; void solve() { int i,mx,id; mx=0; for(i=1;i<len;i++) { if(mx>i){ p[i]=min(p[2*id-i],p[id]+id-i); } else p[i]=1; for(;str[p[i]+i]==str[i-p[i]];p[i]++) ; if(p[i]+i>mx){ mx=p[i]+i; id=i; } } } void init() { str[0]=-1;str[1]=-2; for(int i=0;i<len;i++) { str[i*2+2]=a[i]; str[i*2+3]=-2; } len=len*2+2; str[len]=-2; } int main() { int i,j,k,T,t=0; scanf("%d",&T); while(T--) { t++; scanf("%d",&len); memset(p,0,sizeof(p)); for(i=0;i<len;i++) {scanf("%d",&a[i]); // s[i]=a[i]+'0'; } init(); solve(); int ans=0; int maxi=0; int f=0; for(i=1;i<len;i+=2) { for(j=i+p[i]-1;j-i>maxi;j-=2) //只要看-2的位置即可。 { if(j-p[j]+1<=i){ maxi=j-i; break; } } } maxi=maxi/2*3; printf("Case #%d: ",t); printf("%d\n",maxi); } return 0; } /* 14 1 2 2 1 1 2 3 3 2 1 1 2 3 4 */ /* 100 15 1 2 3 4 5 5 4 3 2 1 1 2 3 4 5 15 3 4 5 5 4 3 2 1 1 2 3 4 5 5 4 10 2 3 4 4 3 2 2 3 4 4 11 1 1 2 3 3 2 1 1 2 3 3 */
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu5371 Hotaru's problem(manacher 算法+枚举)
原文地址:http://blog.csdn.net/aaaaacmer/article/details/47731583