hdu 3068 and ural 1297


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

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

aaaa

aaa

答案两个都是4,n值计算错误,应该为n = 1<hdu3068采用了比较快的getchar()读入后,也就跑了250ms,不知道那些跑了100+ms的是怎么写的,ORZ。。。。。。

hdu3068

#include 
#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[n] = 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 
#include 

#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< 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[n] = 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 
#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[n] = 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]);
}



你可能感兴趣的:(后缀数组,hduoj)