URAL-1297 Palindrome (最长回文子串)

Palindrome

Time Limit: 1000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u

Description

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» security service would have already started an undercover operation to establish the agent’s identity, but, fortunately, the letter describes communication channel the agent uses. He will publish articles containing stolen data to the “Solaris” almanac. Obviously, he will obfuscate the data, so “Robots Unlimited” will have to use a special descrambler (“Robots Unlimited” part number NPRx8086, specifications are kept secret).

Having read the letter, the “U.S. Robots” president recalled having hired the “Robots Unlimited” ex-employee John Pupkin. President knows he can trust John, because John is still angry at being mistreated by “Robots Unlimited”. Unfortunately, he was fired just before his team has finished work on the NPRx8086 design.

So, the president has assigned the task of agent’s message interception to John. At first, John felt rather embarrassed, because revealing the hidden message isn’t any easier than finding a needle in a haystack. However, after he struggled the problem for a while, he remembered that the design of NPRx8086 was still incomplete. “Robots Unlimited” fired John when he was working on a specific module, the text direction detector. Nobody else could finish that module, so the descrambler will choose the text scanning direction at random. To ensure the correct descrambling of the message by NPRx8086, agent must encode the information in such a way that the resulting secret message reads the same both forwards and backwards. 
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.

Your task is to help John Pupkin by writing a program to find the secret message in the text of a given article. As NPRx8086 ignores white spaces and punctuation marks, John will remove them from the text before feeding it into the program.

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 there are several such strings you should output the first of them.

Sample Input

input output
ThesampletextthatcouldbereadedthesameinbothordersArozaupalanalapuazorA
ArozaupalanalapuazorA
/*
 * URAL 1297 Palindrome
 * 求一个字符串的最长回文子串
 *
 * 考虑用后缀数组做,首先在字符串后面加一个不会出现的字符,再将原串反转接到原串的后面,
 * 得到一个长度为2*len+1的新字符串,求出后缀数组和height数组
 * 考虑这个性质,如果一个字符串有回文子串,那么按照上面构造的新字符串的对称部分有相同的前缀
 * 这样我们就可以枚举这个回文串的中心字符,然后求出这个位置和对称位置的lcp,这个的两倍就是
 * 回文串的长度,根据height数组的性质,lcp(i,j)=min(height[rank[i]+1],....,height[rank[j]])
 * 这个是区间最小值,用rmq或者线段树等都可以在O(n*logn)的复杂度内求出来,这样枚举每个位置,再取
 * 一个最大值就可以了,当然枚举的回文中心有奇数和偶数之分,都算一下就ok了,这样总的复杂度就是
 * O(n*n*logn),就可以ac了。
 */

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 2000+100;

int sa[MAXN];
int t1[MAXN],t2[MAXN],c[MAXN];
int Rank[MAXN],height[MAXN];
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;
    }
}
struct SparseTable
{
    int rmq[MAXN];
    int mm[MAXN];
    int dp[MAXN][20];
    void init(int n)
    {
        mm[0]=-1;
        for(int i=1;i<=n;i++)
        {
            mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
            dp[i][0]=i;
        }
        for(int j=1;j<=mm[n];j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)
    {
        if(a>b) swap(a,b);
        int k=mm[b-a+1];
        return rmq[dp[a][k]]<=rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
}ST;
int lcp(int a,int b)
{
    a=Rank[a],b=Rank[b];
    if(a>b) swap(a,b);
    return height[ST.query(a+1,b)];
}
int ss[MAXN];
char str[MAXN];

int main()
{
    scanf("%s",str);
    int len=strlen(str);
    int n=2*len+1;
    for(int i=0;i<len;i++) ss[i]=str[i];
    ss[len]=1;
    for(int i=0;i<len;i++) ss[n-i-1]=str[i];
    ss[n]=0;
    build_sa(ss,n+1,128);
    getHeight(ss,n);
    for(int i=1;i<=n;i++) ST.rmq[i]=height[i];
    ST.init(n);
    int st,ans=0;
    for(int i=0;i<len;i++)
    {
        int tmp=lcp(i,n-i);
        if(2*tmp>ans)//偶对称
        {
            ans=2*tmp;
            st=i-tmp;
        }
        tmp=lcp(i,n-i-1);
        if(2*tmp-1>ans)//奇对称
        {
            ans=2*tmp-1;
            st=i-tmp+1;
        }
    }
    str[ans+st]=0;
    printf("%s\n",str+st);
    return 0;
}
时间: 2024-12-22 07:16:07

URAL-1297 Palindrome (最长回文子串)的相关文章

URAL 1297 求最长回文字符串

有种简单的方法,数组从左到右扫一遍,每次以当前的点为中心,只要左右相等就往左右走,这算出来的回文字符串是奇数长度的 还有偶数长度的回文字符串就是以当前扫到的点和它左边的点作为中心,然后往左右扫 这是O(n^2)的复杂度,这道题过还是没有问题的 这里我主要练习的是另外的利用后缀数组加RMQ算法来解决这个问题 大致思想跟上面一致 首先将字符串反转贴在原字符串末尾,将字符通过ASCII码转化为字符,之间用一个1分开,最后贴一个0 然后得到它的后缀数组以及height[]数组 那么找回文字符也是扫一遍,

【URAL 1297】Palindrome 最长回文子串

模板题,,,模板打错查了1h+QAQ #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 1000003; int t1[N], t2[N], c[N], f[N][30]; void st(int *x, int *y, int *sa, int n, int m) { int i; for(i =

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 【最长回文子串】

最长回文子串 相关资料: 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

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

Description 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? security service would have alrea

URAL 1297 后缀数组:求最长回文子串

思路:这题下午搞了然后一直WA,后面就看了Discuss,里面有个数组:ABCDEFDCBA,这个我输出ABCD,所以错了. 然后才知道自己写的后缀数组对这个回文子串有bug,然后就不知道怎么改了. 然后看题解,里面都是用RMQ先预处理任意两个后缀的最长公共前缀,因为不太知道这个,所以又看了一下午,嘛嘛-- 然后理解RMQ和后缀一起用的时候才发现其实这里不用RMQ也可以,只要特殊处理一下上面这个没过的例子就行了,哈哈--机智-- 不过那个国家集训队论文里面正解是用RMQ做的,自己还得会和RMQ一

后缀数组 - 求最长回文子串 + 模板题 --- ural 1297

1297. Palindrome Time Limit: 1.0 secondMemory Limit: 16 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» s

最长回文子串算法

#1032 : 最长回文子串 时间限制:1000ms 单点时限:1000ms 内存限制:64MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. 这一天,他们遇到了一连串的字符串,于是小Hi就向小Ho提出了那个经典的问题:"小Ho,你能不能分别在这些字符串中找到它们每一个的最长回文子串呢?" 小Ho奇怪的问道:"什么叫做最长回文子串呢?" 小Hi回答道:"一个字符串中连续的一

Palindrome Partitioning (回文子串题)

Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. For example, given s = "aab",Return [ ["aa","b"], ["a","a","