ural 1297 最長迴文子串 字尾陣列

life4711發表於2014-08-05

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 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 output
ThesampletextthatcouldbereadedthesameinbothordersArozaupalanalapuazorA
ArozaupalanalapuazorA
題目大意:

                   給定一個字串,求出其最長迴文子串,若有長度相同的,輸出最左邊的。

解題思路:

                  字尾陣列的應用,首先,將原串倒置後拼接在其後,二者之間新增一個絕對不會再字串中出現的字元作為分隔。然後求取拼接後的字串字尾的最長公共字首就是答案。窮舉每一位i,以i為中心的最長迴文串,則只需要求出i+1和i-1倒過來的字尾最長公共字首,或者求出i和i-1(偶數長度迴文串)倒過來的最長公共字首,所以只需要將原串反轉放到原串後面然後求出height再用LCP列舉求出長度即可。

 

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn=211111;
/******************************************************************
**  字尾陣列 Suffix Array
**  INIT:solver.call_fun(char* s);
**  CALL: solver.lcp(int i,int j); //字尾i與字尾j的最長公共字首
**  SP_USE: solver.LCS(char *s1,char* s2); //最長公共字串
******************************************************************/
struct SuffixArray
{
    int r[maxn];
    int sa[maxn],rank[maxn],height[maxn];
    int t[maxn],t2[maxn],c[maxn],n;
    int m;//模板長度
    void init(char* s)
    {
        n=strlen(s);
        for (int i=0; i<n; i++) r[i]=int(s[i]);
        m=300;
    }
    int cmp(int *r,int a,int b,int l)
    {
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    /**
    字元要先轉化為正整數
    待排序的字串放在r[]陣列中,從r[0]到r[n-1],長度為n,且最大值小於m。
    所有的r[i]都大於0,r[n]無意義演算法中置0
    函式結束後,結果放在sa[]陣列中(名次從1..n),從sa[1]到sa[n]。s[0]無意義
    **/
    void build_sa()
    {
        int i,k,p,*x=t,*y=t2;
        r[n++]=0;
        for (i=0; i<m; i++) c[i]=0;
        for (i=0; i<n; i++) c[x[i]=r[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 (k=1,p=1; k<n; k*=2,m=p)
        {
            for (p=0,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=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]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
        }
        n--;
    }
    /**
    height[2..n]:height[i]儲存的是lcp(sa[i],sa[i-1])
    rank[0..n-1]:rank[i]儲存的是原串中suffix[i]的名次
    **/
    void getHeight()
    {
        int i,j,k=0;
        for (i=1; i<=n; i++) rank[sa[i]]=i;
        for (i=0; i<n; i++)
        {
            if (k) k--;
            j=sa[rank[i]-1];
            while (r[i+k]==r[j+k]) k++;
            height[rank[i]]=k;
        }
    }
    int d[maxn][20];
    //元素從1編號到n
    void RMQ_init(int A[],int n)
    {
        for (int i=1; i<=n; i++) d[i][0]=A[i];
        for (int j=1; (1<<j)<=n; j++)
            for (int i=1; i+j-1<=n; i++)
                d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
    }
    int RMQ(int L,int R)
    {
        int k=0;
        L=rank[L];
        R=rank[R];
        if(L>R) swap(L,R);
        L++;
        while ((1<<(k+1))<=R-L+1) k++;
        return min(d[L][k],d[R-(1<<k)+1][k]);
    }
    void LCP_init()
    {
        RMQ_init(height,n);
    }
    int lcp(int i,int j)
    {
        if (rank[i]>rank[j]) swap(i,j);
        return RMQ(rank[i]+1,rank[j]);
    }
    void call_fun(char* s)
    {
        init(s);//初始化字尾陣列
        build_sa();//構造字尾陣列sa
        getHeight();//計算height與rank
        LCP_init();//初始化RMQ
    }
} solver;
int main()
{
    char s[maxn],r[maxn];
    while(~scanf("%s",s))
    {
        int n=strlen(s),len=n;
        s[n]='#';
        for(int i=n-1;i>=0;--i)
            s[++n]=s[i];
        s[++n]='\0';
        for(n=0;s[n]!='\0';++n)
            r[n]=s[n];
        r[n]=0;
        solver.call_fun(r);
        int sum=1,id=0;
        for(int i=1;i<len;i++)
        {
            if(2*solver.RMQ(i+1,n-i)+1>sum)
                  sum=2*solver.RMQ(i+1,n-i)+1,id=i-solver.RMQ(i+1,n-i);
            if(2*solver.RMQ(i,n-i)>sum)
                  sum=2*solver.RMQ(i,n-i),id=i-solver.RMQ(i,n-i);
        }
        for(int i=id;i<id+sum;i++)
            cout<< s[i];
        cout<<endl;
    }
    return 0;
}
/**
ThesampletextthatcouldbereadedthesameinbothordersArozaupalanalapuazorA
**/


相關文章