poj 2774

题目概述:

有两个字符串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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值