POJ2774 很长的信息

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

 

题解:

将两串合并,中间插入一个'#'保证high不会交叉

然后需要做的是枚举两个后缀sa[i],sa[j],满足sa[i],sa[j]分别在 '#'的两侧。

若sa[i],sa[j]在'#'的两侧,则存在i<=k<=j,满足sa[k]与sa[k+1]在'#'的两侧,

又由于lcp(i,j)<=lcp(k,k+1),故只需要枚举相邻两个后缀即可。

 

 

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 using namespace std;
 8 const int N=200005;
 9 char S1[N],S2[N];int s[N],n,c[N],sa[N],y[N],x[N],rk[N];
10 bool comp(int i,int j,int k){
11     return y[i]==y[j] && y[i+k]==y[j+k];
12 }
13 void getSA(){
14     int m=31,t=0;
15     for(int i=0;i<=m;i++)c[i]=0;
16     for(int i=1;i<=n;i++)c[x[i]=s[i]]++;
17     for(int i=1;i<=m;i++)c[i]+=c[i-1];
18     for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
19     for(int k=1;k<=n;k<<=1){
20         t=0;
21         for(int i=0;i<=m;i++)y[i]=0;
22         for(int i=n-k+1;i<=n;i++)y[++t]=i;
23         for(int i=1;i<=n;i++)if(sa[i]>k)y[++t]=sa[i]-k;
24         for(int i=0;i<=m;i++)c[i]=0;
25         for(int i=1;i<=n;i++)c[x[i]]++;
26         for(int i=1;i<=m;i++)c[i]+=c[i-1];
27         for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i];
28         swap(x,y);
29         t=x[sa[1]]=1;
30         for(int i=2;i<=n;i++)x[sa[i]]=comp(sa[i-1],sa[i],k)?t:++t;
31         if(t==n)break;
32         m=t;
33     }
34     for(int i=1;i<=n;i++)rk[sa[i]]=i;
35 }
36 int high[N];
37 void gethight(){
38     int h=0,j;
39     for(int i=1;i<=n;i++){
40         j=sa[rk[i]-1];
41         if(h>0)h--;
42         for(;j+h<=n && i+h<=n;h++)
43             if(s[i+h]!=s[j+h])break;
44         high[rk[i]-1]=h;
45     }
46 }
47 void work()
48 {
49     n=0;
50     scanf("%s%s",S1,S2);
51      for(int i=0,sz=strlen(S1);i<sz;i++)s[++n]=S1[i]-'a'+1;
52     s[++n]=30;
53     for(int i=0,sz=strlen(S2);i<sz;i++)s[++n]=S2[i]-'a'+1;
54     getSA();
55     gethight();
56     int ans=0;int tx=strlen(S1);
57     for(int i=1;i<n;i++)if(high[i]>ans && ((sa[i]<=tx)!=(sa[i+1]<=tx)))ans=high[i];
58     printf("%d\n",ans);
59 }
60 
61 int main()
62 {
63     work();
64     return 0;
65 }

 

 

 

posted @ 2017-07-11 21:28  PIPIBoss  阅读(683)  评论(2编辑  收藏  举报