zoukankan      html  css  js  c++  java
  • 后缀数组 POJ 3974 Palindrome && URAL 1297 Palindrome

    题目链接

    题意:求给定的字符串的最长回文子串

    分析:做法是构造一个新的字符串是原字符串+反转后的原字符串(这样方便求两边回文的后缀的最长前缀),即newS = S + '$' + revS,枚举回文串中心位置,RMQ询问LCP = min (height[rank[l]+1] to height[rank[r]]),注意的是RMQ传入参数最好是后缀的位置,因为它们在树上的顺序未知,且左边还要+1。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    const int N = 1e3 + 10;
    const int D = 21;
    char s[N];
    int sa[N<<1], t[N<<1], t2[N<<1], c[N<<1], n;
    int rank[N<<1], height[N<<1];
    int dp[N<<1][D];
    
    
    void da(char *s, int m = 256) {
        int i, *x = t, *y = t2;
        for (i=0; i<m; ++i) c[i] = 0;
        for (i=0; i<n; ++i) c[x[i]=s[i]]++;
        for (i=1; i<m; ++i) c[i] += c[i-1];
        for (i=n-1; i>=0; --i) sa[--c[x[i]]] = i;
        for (int k=1; k<=n; k<<=1) {
            int p = 0;
            for (i=n-k; i<n; ++i) y[p++] = i;
            for (i=0; i<n; ++i) if (sa[i] >= k) y[p++] = sa[i] - k;
            for (i=0; i<m; ++i) c[i] = 0;
            for (i=0; i<n; ++i) c[x[y[i]]]++;
            for (i=0; i<m; ++i) c[i] += c[i-1];
            for (i=n-1; i>=0; --i) sa[--c[x[y[i]]]] = y[i];
            std::swap (x, y);
            p = 1; x[sa[0]] = 0;
            for (i=1; i<n; ++i) {
                x[sa[i]] = y[sa[i-1]] == y[sa[i]]
                    && y[sa[i-1]+k] == y[sa[i]+k] ? p - 1 : p++;
            }
            if (p >= n) break;
            m = p;
        }
        //height[i] = LCP (s[sa[i-1]], s[sa[i]]);
        int j, k = 0;
        for (i=0; i<n; ++i) rank[sa[i]] = i;
        for (i=0; i<n; ++i) {
            if (k) k--;
            int j = sa[rank[i]-1];
            while (s[i+k] == s[j+k]) k++;
            height[rank[i]] = k;
        }
    }
    
    int query_RMQ(int l, int r) {
        l = rank[l]; r = rank[r];
        if (l > r) {
            std::swap (l, r);
        }
        l++;
        int k = 0; while (1<<(k+1) <= r - l + 1) k++;
        return std::min (dp[l][k], dp[r-(1<<k)+1][k]);
    }
    void init_RMQ(int *height) {
        //memset (dp, 0, sizeof (dp));
        for (int i=0; i<=n; ++i) {
            dp[i][0] = height[i];
        }
        for (int j=1; (1<<j)<=n; ++j) {
            for (int i=0; i+(1<<j)<=n; ++i) {
                dp[i][j] = std::min (dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
            }
        }
    }
    
    int run(char *s) {
        int len = strlen (s);
        n = len;
        s[n++] = '$';
        for (int i=len-1; i>=0; --i) {
            s[n++] = s[i];
        }
        s[n++] = '';
        da (s);
        init_RMQ (height);
        int ret = 0;
        for (int i=0; i<len; ++i) {
            int l = query_RMQ (i, n-i-2); //奇数
            ret = std::max (ret, 2 * l - 1);
            l = query_RMQ (i, n-i-1);  //偶数
            ret = std::max (ret, 2 * l);
        }
        return ret;
    }
    
    int main() {
        int cas = 0;
        while (scanf ("%s", s) == 1) {
            if (strcmp (s, "END") == 0) {
                break;
            }
            printf ("Case %d: %d
    ", ++cas, run (s));
        }
        return 0;
    }
    

    URAL 1297 题目没什么区别,数据规模小了,还要输出回文串。

    核心代码

    int best = 0;
    from = 0; to = 1;
    for (int i=0; i<len; ++i) {
        int l = query_RMQ (i, n-i-1);
        if (best < 2 * l - 1) {
            from = i - l + 1; to = i + l;
            best = 2 * l - 1;
        }
        l = query_RMQ (i, n-i);
        if (best < 2 * l) {
            from = i - l; to = i + l;
            best = 2 * l;
        }
    }    
    

      

  • 相关阅读:
    Python:完全数
    Python:将 list 写入一个 txt 文件
    Python:对称数组
    Python:列表反转、切片
    Python:print输出间隔,换行
    Python:打印99乘法表
    Python:排序(sort / 冒泡排序)
    安装pipenv
    flex布局
    python正则表达式
  • 原文地址:https://www.cnblogs.com/Running-Time/p/5448855.html
Copyright © 2011-2022 走看看