poj 2752

来源:互联网 发布:sql注入攻击与防御pdf 编辑:程序博客网 时间:2024/06/15 05:00

题目概述

给定一个字符串str,求所有符合条件的前缀长度,使此长度的前缀与等长的后缀匹配

时限

2000ms/6000ms

输入

每行一个字符串,输入到EOF为止

限制

1<=字符串长度<=4e5

输出

每行若干个数,为符合条件的前缀长度按升序排列,每个数字后跟一空格

样例输入

ababcababababcabab
aaaaa

样例输出

2 4 9 18
1 2 3 4 5

讨论

字符串,kmp算法中next数组的应用,只要知道next数组中每个值的意义是由其前面的字符构成的子串中,互相匹配的最长前缀后缀的长度,也就是这个题所求的东西,比如第一组样例,从最后一个字符开始看next数组(假设已经求得next数组),字符串长18,next[18]为9,说明整个字符串最长长度为9的前缀和后缀是匹配的,下面看看有没有短一点的,既然长度9的前缀后缀都一样,那整个字符串的其他前缀也就是长度9的前缀的前缀,整个字符串的其他后缀也就是长度9的后缀的后缀,也就是长度9的前缀的后缀,好绕口……但确实如此,因而接下来只要考察长度9的前缀(其实考察后缀也一样)即可,长度9,next[9]为4,字符串被分成三部分,前缀,长度4,中间没用的部分,长度1,后缀,长度4,然后遵循之前的思想,继续递归找下去,直到某个next的值为0为止,最后输出
等一下,为什么next数组的意义是这个?实际上因为kmp的思想就是这个,每次不要让模式串的指针都回溯到头,所以需要找到模式串自己和自己匹配的长度,确切说是对于模式串所有前缀,找出(前缀的)最长的前缀,使其与(前缀的)这个长度的后缀匹配,当然,找到的长度自然不能(也不可能)是自身长度,这也就是为什么上面的例子中next[18]为9,而不是next[17](str[17]是字符串的最后一个非空白字符,str[18]是\0),所以说,人家算法就这么设计的,意义自然是这个

题解状态

2632K,125MS,C++,702B

题解代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>//这些都是计算几何的遗留产物 不用管他们using namespace std;#define INF 0x3f3f3f3f#define MAXN 400003#define memset0(a) memset(a,0,sizeof(a))#define EPS 1e-8int Next[MAXN];//next数组 不是next因为iterator头文件中有函数next 使得迭代器向容器后方移动若干个位置 真不巧char str[MAXN];//string 原始字符串int stk[MAXN], top;//stack 数组模拟栈及其栈顶 因为要升序输出void calNext(int len)//calculate_next 额也不明白其正确性 不过所幸不难背过 一般也不会对这个函数下手{    int p = 0, i = -1;    Next[0] = -1;    while (p < len)        if (i == -1 || str[p] == str[i])            Next[++p] = ++i;        else            i = Next[i];}int main(void){    //freopen("vs_cin.txt", "r", stdin);    //freopen("vs_cout.txt", "w", stdout);    while (~scanf("%s", str)) {//input        int len = strlen(str);//读取长度备用        calNext(len);        while (len) {            stk[top++] = len;//首先字符串自身的长度必然符合条件 但是next数组中不会有这个值 因而先把自己压栈            len = Next[len];//然后再将字符串划分寻找较小的前缀长度        }        for (; top; top--)            printf("%d ", stk[top - 1]);//output//退栈输出        printf("\n");//output    }}

EOF

0 0
原创粉丝点击