后缀数组 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++] = ‘\0‘;
    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\n", ++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;
    }
}

  

时间: 2024-10-20 18:38:05

后缀数组 POJ 3974 Palindrome && URAL 1297 Palindrome的相关文章

Ural 1297 Palindrome(Manacher或者后缀数组+RMQ-ST)

1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The “U.S. Robots” HQ has just received a rather alarming anonymous letter. It states that the agent from the competing «Robots Unlimited» has infiltrated into “U.S. Robotics”. «U.S. Robots»

URAL 1297 Palindrome 后缀数组

1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots Unlimited? has infiltrated into "U.S. Robotics".

URAL 1297. Palindrome(后缀数组求最大回文串)

题目大意:给你一串字符串,让你求出来它存在的最长连续的回文串. 解题思路:先把字符串逆序加到数组中,然后用后缀数组求解.两种方法:1,枚举排名,直接比较rank相同的字符串的位置差是不是len.如果是的话,就记录求解:2,枚举地址,求第i地址与第2*len-i+1的lcp的最大值. PS:需要注意如果多解输出靠前的字符串. 两种写法写在了一起,分别是Del,和Del1函数. 1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB T

URAL 1297. Palindrome(输出最长回文子串--后缀数组)

Input The input consists of a single line, which contains a string of Latin alphabet letters (no other characters will appear in the string). String length will not exceed 1000 characters. Output The longest substring with mentioned property. If ther

URAL 1297. Palindrome(后缀数组 求最长回文子串)

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1297 1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots

URAL 1297 Palindrome(后缀数组+ST表)

[题目链接] http://acm.timus.ru/problem.aspx?num=1297 [题目大意] 求最长回文子串,并输出这个串. [题解] 我们将原串倒置得到一个新的串,加一个拼接符将新串拼在原串的后面, 那么枚举对称的中心点, 在两个串在组合成的串的对应位置的后缀的最长公共前缀 就是该点像两边扩展的最长回文子串的一半长度. 那么如何求任意两个后缀的最长公共前缀呢,考虑后缀数组的h数组和rank数组, 我们可以发现,两个后缀的最长公共前缀就是他们名次之间的h数组的最小值. 对h数组

URAL 1297 Palindrome

Palindrome Time Limit: 1000ms Memory Limit: 16384KB This problem will be judged on Ural. Original ID: 129764-bit integer IO format: %lld      Java class name: (Any) The “U.S. Robots” HQ has just received a rather alarming anonymous letter. It states

ural 1297 Palindrome(Manacher模板题)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 求最长回文子串. http://acm.timus.ru/problem.aspx?space=1&num=1297 Manacher模板题,复杂度O(n),做这题纯属是为了验一下自己写的模板是否正确. 当然这题也可以用后缀数组来搞 1 #include <iostream> 2 #include <sstream> 3 #include <ios&g

Ural 1297 Palindrome 【最长回文子串】

最长回文子串 相关资料: 1.暴力法 2.动态规划 3.中心扩展 4.Manacher法 http://blog.csdn.net/ywhorizen/article/details/6629268 http://blog.csdn.net/kangroger/article/details/37742639 在看后缀数组的时候碰到的这道题目 不过没用后缀数组写出来= = 用了一个很暴力的做法卡进了1 s Source Code: //#pragma comment(linker, "/STAC