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 }