您的位置:首页 > 其它

后缀数组 - poj2774 Long Long Message

2015-09-02 11:22 489 查看

题目:

http://poj.org/problem?id=2774

题意:

给两个字符串,求最大公共子串的长度

思路:

后缀数组模板题,我是拿这题来入门后缀数组的

在两个字符串中插入一个比两个字符串中任一字符小的字符,在本题中即插入一个('a'-1),然后合并两个字符串,在其他题解中会看到,当合并多个字符串时,要在每个间隔都加上一个不同的逼所有字符串中任一字符小的字符。然后对合并完的字符串求后缀数组,因为间隔字符的存在,height数组中记录的lcp值不会越过第一个字符串到达第二个,这一点很重要,一定要理解为什么要插入不同的字符,而保证插入字符小于串中任意字符是为了保证,每个字符串的后缀数组能够与独立情况下求得的后缀数组一致,因为在独立情况下,字符串结尾字符为'\0',即默认结尾字符小于任一字符。之后遍历height数组,找到lcp最大,且两个后缀串分别位于第一个和第二个字符串的后缀即可

代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>

#define rep(i,n) for(int i = 0;i < n; i++)
using namespace std;

const int MAXSIZE  = 2*1e6 + 100;
int rk[MAXSIZE],sa[MAXSIZE],height[MAXSIZE],wa[MAXSIZE],res[MAXSIZE];
char w[MAXSIZE];
int len;

void getSa (int up) {
int *k = rk,*id = height,*r = res, *cnt = wa;
rep(i,up) cnt[i] = 0;
rep(i,len) cnt[k[i] = w[i]]++;
rep(i,up) cnt[i+1] += cnt[i];
for(int i = len - 1; i >= 0; i--) {
sa[--cnt[k[i]]] = i;
}
int d = 1,p = 0;
while(p < len){
for(int i = len - d; i < len; i++) id[p++] = i;
rep(i,len)  if(sa[i] >= d) id[p++] = sa[i] - d;
rep(i,len) r[i] = k[id[i]];
rep(i,up) cnt[i] = 0;
rep(i,len) cnt[r[i]]++;
rep(i,up) cnt[i+1] += cnt[i];
for(int i = len - 1; i >= 0; i--) {
sa[--cnt[r[i]]] = id[i];
}
swap(k,r);
p = 0;
k[sa[0]] = p++;
rep(i,len-1) {
if(sa[i]+d < len && sa[i+1]+d < len && r[sa[i]] == r[sa[i+1]] && r[sa[i]+d] == r[sa[i+1]+d])
k[sa[i+1]] = p - 1;
else k[sa[i+1]] = p++;
}
if(p >= len) return ;
d <<= 1,up = p, p = 0;
}
}
void getHeight() {
int i,k,h=0;
rep(i, len) rk[sa[i]]=i;
rep(i, len){
if (rk[i]==0)
h=0;

a494
else
{
k=sa[rk[i]-1];
if (h) h--;
while (w[i+h] == w[k+h]) h++;
}
height[rk[i]]=h;
}
}

int l;
char s[MAXSIZE], t[MAXSIZE];

void getSuffix(char s[]) {
l = strlen(s);
s[l] = 'a' - 1;
s[l+1] = 0;
strcat(s,t);
//cout<<s<<endl;
len = strlen(s);
int up = 0;
for(int i = 0; i < len; i++) {
w[i] = s[i] - 'a' + 2;
up = up > w[i] ? up : w[i];
}
w[len+1] = 0;
getSa(up+1);
getHeight();
}

int main(){
scanf("%s",s);
scanf("%s",t);

getSuffix(s);
int maxinum = 0;
for (int i=1;i<len;++i){
if (height[i]>maxinum)
if ((sa[i-1]<l && sa[i]>l) || (sa[i-1]>l && sa[i]<l))
maxinum = height[i];
}
cout<<maxinum<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: