1. 程式人生 > >【POJ2774】Long Long Message(後綴數組)

【POJ2774】Long Long Message(後綴數組)

火車票 字符串 cat ios swa char 們的 same getc

【POJ2774】Long Long Message(後綴數組)

題面

Vjudge

Description

Little cat在Byterland的首都讀物理專業。這些天他收到了一條悲傷地信息:他的母親生病了。擔心買火車票花錢太多(Byterland是一個巨大的國家,因此他坐火車回家需要16小時),他決定只給母親發短信。
Little cat的家境並不富裕,因此他經常去營業廳查看自己發短信花了多少錢。昨天營業廳的電腦壞掉了,打印出兩條很長的信息。機智的little cat很快發現:
1.信息中所有的字符都是小寫英文字母,沒有標點和空格。
2.所有的短信都被連在了一起——第i+1條短信直接接在第i條短信後面——這就是這兩條信息如此長的原因。

3.雖然他發的短信都被連在了一起,但由於電腦壞掉了,它們的左邊或右邊都可能會有許多冗余字符。
例如:如果短信是"motheriloveyou",電腦打印出的每條信息都可能是 "hahamotheriloveyou", "motheriloveyoureally", "motheriloveyouornot", "bbbmotheriloveyouaaa",等等。
4.因為這些亂七八糟的問題,little cat打印了兩遍(所以有兩條非常長的信息)。盡管原始的短信文本在兩條信息中都一樣,但兩條信息在文本兩側的冗余字符都可能不一樣。
給出這兩條很長的信息,輸出little cat寫下的原始短信文本的最長可能長度。
背景:
在Byterland,短信按照美元/字節的單位計價。這就是little cat想要知道原始文本最長可能長度的原因。
為什麽讓你寫一個程序?有四個原因:
1.little cat這些天忙於他的物理課程。
2.little cat不想透露他對母親說了什麽。
3.POJ是個好網站。
4.little cat想要從POJ那裏掙點錢,並嘗試說服他的母親去醫院

Input

兩行兩個由小寫英文字母組成的字符串。字符串長度都不會超過100000

Output

一行一個整數,即little cat寫下的原始文本的最長可能長度。

Sample Input

yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
yeaphowmuchiloveyoumydearmother

Sample Output

27

題解

把兩個串接起來
現在問題就可以轉換成
找兩個後綴
求他們的最長公共前綴的最大值

這個最大值顯然是一個\(height\)的值
因為是要從兩個串中各選出一個串
所以要判斷\(SA[i]\)\(SA[i-1]\)是否在兩個不同的串中

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 220000
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
char ch[MAX];
int SA[MAX],x[MAX],y[MAX],t[MAX];
int Rank[MAX],height[MAX],a[MAX];
int n,n1,n2;
bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
bool same(int i,int j){return ((i<=n1)&&(j<=n1))|((i>n1)&&(j>n1));}
void GetSA()
{
    int m=30;
    for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
    for(int i=1;i<=m;++i)t[i]+=t[i-1];
    for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1)
    {
        int p=0;
        for(int i=0;i<=n;++i)y[i]=0;
        for(int i=n-k+1;i<=n;++i)y[++p]=i;
        for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
        for(int i=0;i<=m;++i)t[i]=0;
        for(int i=1;i<=n;++i)t[x[y[i]]]++;
        for(int i=1;i<=m;++i)t[i]+=t[i-1];
        for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
        swap(x,y);
        x[SA[1]]=p=1;
        for(int i=2;i<=n;++i)x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
        if(p>=n)break;
        m=p;
    }
    for(int i=1;i<=n;++i)Rank[SA[i]]=i;
    for(int i=1,j=0;i<=n;++i)
    {
        if(j)j--;
        while(a[i+j]==a[SA[Rank[i]-1]+j])++j;
        height[Rank[i]]=j;
    }
}
int main()
{
    scanf("%s",ch+1);
    n=n1=strlen(ch+1);
    for(int i=1;i<=n1;++i)a[i]=ch[i]-96;
    scanf("%s",ch+1);
    for(int i=1,l=strlen(ch+1);i<=l;++i)a[++n]=ch[i]-96;
    n2=n-n1;
    GetSA();
    int ans=0;
    for(int i=2;i<=n;++i)
        if(!same(SA[i],SA[i-1]))
            ans=max(ans,height[i]);
    printf("%d\n",ans);
    return 0;
}

【POJ2774】Long Long Message(後綴數組)