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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章