【POJ2774】Long Long Message(后缀数组)

【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;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8335761.html

时间: 2024-09-30 20:07:02

【POJ2774】Long Long Message(后缀数组)的相关文章

poj2774 Long Long Message(后缀数组or后缀自动机)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes t

POJ2774 Long Long Message [后缀数组]

Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 29277   Accepted: 11887 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days

HUID 5558 Alice&#39;s Classified Message 后缀数组+单调栈+二分

http://acm.hdu.edu.cn/showproblem.php?pid=5558 对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大.这样做O(n^2) 考虑到对于每一个suffix(i),最长的LCP肯定在和他排名相近的地方取得. 按排名大小顺序枚举位置,按位置维护一个递增的单调栈,对于每一个进栈的元素,要算一算栈内元素和他的LCP最大是多少. 如果不需要输出最小的下标,最大的直接是LCP(suffix(st[top]),  suff

PKU 2774 Long Long Message (后缀数组练习模板题)

题意:给你两个字符串,求最长公共字串的长度. by:罗穗骞模板 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define M 303 #define inf 0x3fffffff #define maxn 500000 #define ws ww #define rank RANK #define F

(HDU 5558) 2015ACM/ICPC亚洲区合肥站---Alice&#39;s Classified Message(后缀数组)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5558 Problem Description Alice wants to send a classified message to Bob. She tries to encrypt the message with her original encryption method. The message is a string S, which consists of Nlowercase let

poj 2774 Long Long Message 后缀数组基础题

Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 24756   Accepted: 10130 Case Time Limit: 1000MS Description The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is ge

poj 2774 Long Long Message(后缀数组入门题)

1 /****************************************************************** 2 题目: Long Long Message(poj 2774) 3 链接: http://poj.org/problem?id=2774 4 题意: 给两个字符串,找最长的公共子串 5 算法: 后缀数组 6 算法思想: 后缀数组就是套模板求先应得数组,这题用到了两个数组,分 7 别是sa[],height[];sa[i]表示所有后缀按字典数排序后以s[i

POJ2774Long Long Message (后缀数组&amp;后缀自动机)

问题: The little cat is majoring in physics in the capital of Byterland. A piece of sad news comes to him these days: his mother is getting ill. Being worried about spending so much on railway tickets (Byterland is such a big country, and he has to spe

poj 2774 Long Long Message 后缀数组LCP理解

题目链接 题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少? 思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可: #include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<map> #include<queue&

POJ 2774 Long Long Message ——后缀数组

[题目分析] 用height数组RMQ的性质去求最长的公共子串. 要求sa[i]和sa[i-1]必须在两个串中,然后取height的MAX. 利用中间的字符来连接两个字符串的思想很巧妙,记得最后还需要空一个位置避免冲突. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set>