URAL1297 Palindrome(后缀数组)
2016-02-21 10:40
447 查看
求一个串的最大回文字串。
可以用后缀数组解决。
分别考虑奇数和偶数回文子串的情况,枚举原串S的每个位置i作为中间位置看其能向左右两边同时拓展都哪儿:把原串S反转成S',拼接SaS'(a为一个特殊字符),最远拓展的地方便可以通过LCP(suffix[i],suffix[i'])求得,i'为i对应在S‘的位置。
另外题目要求第一个出现的最长回文串,从左到右枚举中间位置得到的肯定就是出现最早的。
可以用后缀数组解决。
分别考虑奇数和偶数回文子串的情况,枚举原串S的每个位置i作为中间位置看其能向左右两边同时拓展都哪儿:把原串S反转成S',拼接SaS'(a为一个特殊字符),最远拓展的地方便可以通过LCP(suffix[i],suffix[i'])求得,i'为i对应在S‘的位置。
另外题目要求第一个出现的最长回文串,从左到右枚举中间位置得到的肯定就是出现最早的。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define MAXN 2222 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN]; int cmp(int *r,int a,int b,int l){ return r[a]==r[b] && r[a+l]==r[b+l]; } int sa[MAXN],rank[MAXN],height[MAXN]; void SA(int *r,int n,int m){ int *x=wa,*y=wb; for(int i=0; i<m; ++i) ws[i]=0; for(int i=0; i<n; ++i) ++ws[x[i]=r[i]]; for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i; int p=1; for(int j=1; p<n; j<<=1,m=p){ p=0; for(int i=n-j; i<n; ++i) y[p++]=i; for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j; for(int i=0; i<n; ++i) wv[i]=x[y[i]]; for(int i=0; i<m; ++i) ws[i]=0; for(int i=0; i<n; ++i) ++ws[wv[i]]; for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i]; swap(x,y); x[sa[0]]=0; p=1; for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } for(int i=1; i<n; ++i) rank[sa[i]]=i; int k=0; for(int i=0; i<n-1; height[rank[i++]]=k){ if(k) --k; for(int j=sa[rank[i]-1]; r[i+k]==r[j+k]; ++k); } } int st[12][MAXN]; void ST(int *a,int n){ for(int i=1; i<=n; ++i) st[0][i]=a[i]; for(int i=1; i<12; ++i){ for(int j=1; j<=n; ++j){ if(j+(1<<i)>n) break; st[i][j]=min(st[i-1][j],st[i-1][j+(1<<i-1)]); } } } int rmq(int a,int b){ if(a>b) swap(a,b); ++a; int k=(int)(log2(b-a+1)+1e-6); return min(st[k][a],st[k][b-(1<<k)+1]); } char str[MAXN]; int r[MAXN]; int main(){ scanf("%s",str); int n=strlen(str); for(int i=0; i<n; ++i) r[i]=str[i]; r =1; for(int i=n-1; i>=0; --i) r[n+n-i]=str[i]; r[n<<1|1]=0; SA(r,(n<<1|1)+1,128); ST(height,n<<1|1); int res=0; int posi,flag; for(int i=0; i<n; ++i){ if(res<(rmq(rank[i],rank[n+n-i])-1<<1)+1){ res=(rmq(rank[i],rank[n+n-i])-1<<1)+1; posi=i; flag=0; } if(i && res<(rmq(rank[i],rank[n+n-i+1])<<1)){ res=(rmq(rank[i],rank[n+n-i+1])<<1); posi=i; flag=1; } } if(flag){ for(int i=(res>>1); i>=1; --i) putchar(str[posi-i]); for(int i=0; i<(res>>1); ++i) putchar(str[posi+i]); }else{ for(int i=(res>>1); i>=1; --i) putchar(str[posi-i]); putchar(str[posi]); for(int i=1; i<=(res>>1); ++i) putchar(str[posi+i]); } return 0; }
相关文章推荐
- iptables 规则整理
- 联合体(union)的使用方法及其本质
- HDU 4751 Divide Groups(判断二分图)
- 最大公约数与最小公倍数
- CodeForces 630 L. Cracking the Code(水~)
- 【SPOJ-YOUTUBE】Youtube【倍增】
- UIApplication类
- 在easyui datagrid中formatter数据后使用linkbutton
- html基础研究(一)-文本格式化标签研究
- UI整理-----part5--UICollectionView
- c语言入门之项目2.4——利用while求最大公约数
- poj-2411 Mondriaan's Dream (状态压缩dp)
- js实现冒泡排序
- 大端模式与小端模式
- 关于破解AI的补丁和方法
- Android 使用Shell脚本截屏并自动传到电脑上
- 浅谈数字舵机与模拟舵机区别
- CodeForces 630 K. Indivisibility(容斥)
- 用UIInterpolatingMotionEffect产生透视效果
- PHP程序的常见漏洞攻击分析