本文主要是介绍URAL - 1297 Palindrome(后缀数组求最长回文子串),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Description
In addition, it is reasonable to assume that the agent will be sending a very long message, so John has simply to find the longest message satisfying the mentioned property.
Input
Output
Sample Input
input | output |
---|---|
ThesampletextthatcouldbereadedthesameinbothordersArozaupalanalapuazorA | ArozaupalanalapuazorA |
题意:求最长回文子串。
思路:穷举每一位,然后计算以这个字符为中心的最长回文子串。注意这里要分两种情况,一是回文子串的长度为奇数,二是长度为偶数。两种情况都可以转化为求一个后缀和一个反过来写的后缀的最长公共前缀。具体的做法是:将整个字符串反过来写在原字符串后面,中间用一个特殊的字符隔开。这样就把问题变为求这个新的字符串的某两个后缀的最长公共前缀。然后在查找最长公共前缀lcp的时候利用到了RMQ,我们知道对于两个后缀j和k,设rank[j]<rank[k],则不难证明后缀j和k的LCP长度等于height[rank[j]+1],height[rank[j]+2],...,height[rank[k]]中的最小值,
即RMQ(height, rank[j]+1, rank[k]),这是通过height[]数组的两两比较做到的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 2010;int sa[maxn]; //SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[maxn], t2[maxn], c[maxn];
int rank[maxn], height[maxn];
int s[maxn], r[maxn];
char str[maxn];
int st[maxn][20];void build_sa(int s[], int n, int m) {int i, j, p, *x = t1, *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 (j = 1; j <= n; j <<= 1) {p = 0;for (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++) c[i] = 0;for (i = 0; i < n; i++) c[x[y[i]]]++;for (i = 1; i < m; i++) c[i] += c[i-1];for (i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];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]+j] == y[sa[i]+j] ? p-1 : p++;if (p >= n) break;m = p;}
}void getHeight(int s[],int n) {int i, j, k = 0;for (i = 0; i <= n; i++)rank[sa[i]] = i;for (i = 0; i < n; i++) {if (k) k--;j = sa[rank[i]-1];while (s[i+k] == s[j+k]) k++;height[rank[i]] = k;}
}void ST(int n) {for (int i = 1; i <= n; i++)st[i][0] = i;for (int j = 1; (1<<j) <= n; j++) {for (int i = 1; i + (1<<j) <= n; i++) {int p = st[i][j-1]; int q = st[i+(1<<(j-1))][j-1];st[i][j] = height[p] > height[q] ? q : p;}}
}int RMQ(int i, int j) {int k = 0;if (i > j)swap(i, j);i++;while ((1<<(k+1)) <= j-i+1) k++;i = st[i][k];j = st[j-(1<<k)+1][k];return min(height[i], height[j]);
}int main() {while (scanf("%s", str) != EOF) {int len = strlen(str);int n = 2 * len + 1;for (int i = 0; i < len; i++)r[i] = str[i];r[len] = 1;for (int i = 0; i < len; i++)r[i+len+1] = str[len-1-i];r[n] = 0; //noticebuild_sa(r, n+1, 128);getHeight(r, n);ST(n);int mid = n >> 1;int ans = 0, cur = 0;for (int i = 0; i < mid; i++) {int j = RMQ(rank[i], rank[n-i-1]); //奇对称if ((j<<1) - 1 > ans) { ans = (j<<1) - 1;cur = i - j + 1;}if (i) {j = RMQ(rank[i], rank[n-i]); //偶对称if ((j << 1) > ans) {ans = j << 1;cur = i - j;}}}for (int i = cur; i < cur + ans; i++)printf("%c", r[i]);printf("\n");}return 0;
}
这篇关于URAL - 1297 Palindrome(后缀数组求最长回文子串)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!