您的位置:首页 > 其它

hdu 3068 and ural 1297

2013-01-22 22:18 267 查看
两道回文串的题目,关于回文串的题目有很多种解法。以前写回文串的题目都是采用后缀数组写的,今天无意中搜到了Manacher算法,就学了一下。发现Manacher算法真心简洁,复杂度低编程量低。后缀数组写起来得100来行的题目,Manacher写起来不到30行,无限ORZ。。。关于Manacher算法:http://wenku.baidu.com/view/3031d2d3360cba1aa811da42.html

直接看这里就明白了。不过这个文档上的提供的HDOJ3068的代码有点问题。比如数据:

aaaa

aaa

答案两个都是4,n值计算错误,应该为n = 1<<i就可以了。不过杭电的数据水了,将文档上提供的代码交上去竟然也过了。。。。。。hdu3068采用了比较快的getchar()读入后,也就跑了250ms,不知道那些跑了100+ms的是怎么写的,ORZ。。。。。。

hdu3068

#include <stdio.h>
#define  L 110010

char a[L<<1];
int p[L<<1];

int min(int a, int b){
if(a < b) return a;
return b;
}

int main(){
int i, n, id, MaxL, MaxId;
char ch;
while((ch=getchar())!=EOF){
n = 4;
a[0] = '$', a[1] = '#';
a[2] = ch , a[3] = '#';
while((ch = getchar())!='\n'){
a[n ++] = ch, a[n ++] = '#';
}
a
= 0;
MaxL = MaxId = 0;
for(i = 1; i < n; i ++){
if(MaxId > i)
p[i] = min(p[2*id - i], MaxId - i);
else p[i] = 1;
while(a[i+p[i]]==a[i-p[i]]) p[i] ++;
if(p[i] + i > MaxId)
MaxId = p[i] + i, id = i;
if(p[i] > MaxL)
MaxL = p[i] ;
}
printf("%d\n", MaxL - 1);
}
}


ural 1297

后缀数组版:

#include <cstdio>
#include <cstring>

#define maxn 2005
char s[maxn];

int r[maxn], sa[maxn], rank[maxn], height[maxn];
int wa[maxn], wb[maxn], wv[maxn], ws[maxn];

bool cmp(int *arr, int x, int y, int l){
return arr[x]==arr[y]&&arr[x+l]==arr[y+l];
}

void da(int *r, int *sa, int n, int m){
int i, j, p, *x = wa, *y = wb, *t;
for(i = 0; i < m; i ++) ws[i] = 0;
for(i = 0; i < n; i ++) ws[x[i]=r[i]] ++;
for(i = 1; i < m; i ++) ws[i] += ws[i-1];
for(i = n-1; i >= 0; i --)  sa[--ws[x[i]]] = i;

for(j = 1; j <= n; j<<=1){
for(p = 0, i = n - j; i < n; i ++)  y[p ++] = i;
for(i = 0; i < n; i ++) if(sa[i] >= j)  y[p ++] = sa[i] - j;

for(i = 0; i < m; i ++) ws[i] = 0;
for(i = 0; i < n; i ++) ws[wv[i] = x[y[i]]] ++;
for(i = 1; i < m; i ++) ws[i] += ws[i-1];
for(i = n-1; i >= 0; i --)  sa[--ws[wv[i]]] = y[i];

t = x, x = y, y = t;
p = 1, x[sa[0]] = 0;
for(i = 1; i < n; i ++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p - 1 : p ++;
if(p >= n)
break;
m = p;
}
}

void calcHeight(int *r, int *sa, int n){
int i, j, k = 0;
for(i = 1; i <= n; i ++)    rank[sa[i]] = i;
for(i = 0; i < n; height[rank[i ++]] = k)
for(k?k--:0, j = sa[rank[i]-1]; r[i+k]==r[j+k]; k ++);
}

int min(int x, int y){
return x < y ? x : y;
}

//mm[i] = log(i)
int RMQ[maxn][15], mm[maxn];

void initRMQ(int n){
int i, j, a, b;

for(mm[0] = -1, i = 1; i < maxn; i ++){
mm[i] = (i&(i-1)) == 0 ? mm[i-1] + 1 : mm[i-1];
}

for(i = 1; i <= n; i ++) RMQ[i][0] = height[i];

for(j = 1; (1<<j) <= n; j ++)
for(i = 1; i + (1<<j) - 1 <= n; i ++){
RMQ[i][j] = min(RMQ[i][j-1], RMQ[i+(1<<(j-1))][j-1]);
}
}

int query(int a, int b){
int t = mm[b-a+1];
b = b - (1<<t) + 1;
return min(RMQ[a][t], RMQ[b][t]);
}

int lcp(int a, int b){
a = rank[a], b = rank[b];
int t;
if(a > b) t = a, a = b, b = t;
return query(a + 1, b);
}

int main(){
int i, n, len, ans, tmp, loc;
scanf("%s", s);
len = strlen(s);
for(i = 0; i < len; i ++) r[i] = s[i];
r[len] = 1;
for(i = 0; i < len; i ++) r[i + len + 1] = s[len - i - 1];
n = len * 2 + 1;
r
= 0;
da(r, sa, n + 1, 129);
calcHeight(r, sa, n);

initRMQ(n);
ans = 0;
loc = -1;

for(i = 0; s[i]; i++){
tmp = lcp(i, n - i);
if(ans < 2 * tmp)   ans = 2 * tmp , loc = i - tmp;

tmp = lcp(i, n - i- 1);
if(ans < 2 * tmp - 1) ans = 2 * tmp - 1,loc = i - tmp + 1;
}
s[ans + loc] = 0;
printf("%s\n", s+loc);
return 0;
}
Manacher版

#include <stdio.h>
#define M 2010
char a[M];
int p[M];
int min(int a,int b){
return a < b ? a : b;
}
int main(){
char ch;
int i, n, id, MaxL, MaxId, loc;
a[0] = '$', a[1] = '#', n = 2;
while((ch=getchar())!='\n'){
a[n ++] = ch, a[n ++] = '#';
}
MaxL = MaxId = 0, a
= 0;
for(i = 1; i < n; i ++){
if(i < MaxId)   p[i] = min(p[2*id-i], MaxId - i);
else p[i] = 1;
while(a[i+p[i]] ==a[i-p[i]]) p[i]++;
if(i+p[i] > MaxId) MaxId = i + p[i] , id = i;
if(p[i] > MaxL) MaxL = p[i], loc = i;
}
for(i = loc - MaxL + 1; i < loc + MaxL; i ++)
if(a[i]!='#')   putchar(a[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: