您的位置:首页 > 其它

poj 2774

2016-05-19 19:08 363 查看

题目概述:

有两个字符串s,s2

输入:

第一行s,第二行s2

输入只有一组

限制:

s,s2仅含小写字母;s,s2长度<=100000;

输出:

一个整数,最长公共子串的长度

样例输入:

yeshowmuchiloveyoumydearmotherreallyicannotbelieveit

yeaphowmuchiloveyoumydearmother

样例输出:

27

讨论:

题目很长,但其中包含两个关键因素,仅含小写字母和要求最长公共子串,输入中包含第三个因素,长度不过十万,输出包含最后一个因素,求其长度,看完题目这就是个模版题了,因此额也用的模版(然而根本不理解)

算法正确性(fun函数最后几行)没有写,额明白,但是担心写不清楚

题解状态:

3776K,360MS,C++,1693B

题解代码:

#include<string.h>
#include<stdio.h>
#include<iostream>
#include<set>
#include<map>
#include<string>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f
#define maxx(a,b) ((a)>(b)?(a):(b))
#define minn(a,b) ((a)<(b)?(a):(b))
#define MAXN 200006//多数操作建立在两个字符串合并后的基础上,因此是双倍
#define memset0(a) memset(a,0,sizeof(a))

char s[MAXN];//string,最后会合并另一个字符串到这里,因此是双倍
int n, sa[MAXN], height[MAXN], rk[MAXN], tmp[MAXN], top[MAXN];//suffix array,height,rank,temporary,top这一行是模版的数据结构,rank由于和stl有二义性而改名
int s1len, slen;//string 1 length, string length,这里的s1是合并之前的s的长度,s是合并之后的长度
void makesa()//这是模版,倍增算法构造sa数组和rk数组
{
int i, j, len, na;
na = (n < 256 ? 256 : n);
memset(top, 0, na*sizeof(int));
for (i = 0; i < n; i++)
top[rk[i] = s[i] & 0xff]++;
for (i = 1; i < na; i++)
top[i] += top[i - 1];
for (i = 0; i < n; i++)
sa[--top[rk[i]]] = i;
for (len = 1; len < n; len <<= 1) {
for (i = 0; i < n; i++) {
j = sa[i] - len;
if (j < 0)
j += n;
tmp[top[rk[j]]++] = j;
}
sa[tmp[top[0] = 0]] = j = 0;
for (i = 1; i < n; i++) {
if (rk[tmp[i]] != rk[tmp[i - 1]] || rk[tmp[i] + len] != rk[tmp[i - 1] + len])
top[++j] = i;
sa[tmp[i]] = j;
}
memcpy(rk, sa, n*sizeof(int));
memcpy(sa, tmp, n*sizeof(int));
if (j >= n - 1)
break;
}
}
void lcp()//也是模版,求height数组
{
int i, j, k;
for (j = rk[height[i = k = 0] = 0]; i < n - 1; i++, k++)
while (k >= 0 && s[i] != s[sa[j - 1] + k])
height[j] = (k--), j = rk[sa[j] + 1];
}
int fun()
{
char s2[MAXN / 2];//string 2,没什么用的s2字符串
scanf("%s%s", s, s2);//input
s1len = strlen(s);
strcat(s, s2);//合并字符串
slen = strlen(s);
n = strlen(s) + 1;//模版要求的初始化条件
makesa();
lcp();
int big = -INF;//初始化big为一个很小的数
for (int p = 1; p < slen; p++) {//遍历sa数组,由于从s每个位置开始到字符串尾的子串都在sa中,共slen个,以此做限制条件,从1开始因为下面用到p-1
if (sa[p - 1] < s1len&&sa[p] >= s1len || sa[p - 1] >= s1len&&sa[p] < s1len)//如果相邻的后缀分别属于两个字符串
big = maxx(big, height[p]);//更新最大子串长度
}
return big;
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);

printf("%d\n", fun());//output//程序会测试4次,但每次只有一组字符串
}


EOF
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: