【HDU 3518】Boring counting【扩展KMP】

来源:互联网 发布:明华堂淘宝 编辑:程序博客网 时间:2024/06/01 08:42

题意:给出一个串,找出一个最长字串,不重叠的出现次数大于1次,输出这个字串的长度。

思路:我们对母串的每一个后缀都和母串做一遍扩展KMP,这样就可以知道母串和每一个后缀都求出一个最长公共字串的长度,记录ex[i][j]为母串第j个位置开始与第i个后缀所形成的最长公共前缀的长度,则记录maxid[j]表示从母串的j位开始,最长出现次数大于1次且不重叠的字串长度。可以知道maxid[j] = max(maxid[j], min(i-j, ex[i]][j]));

每一个maxid[j]都可以产生maxid[j]个答案,接下来就是对于答案判重的情况。我们可以用字典树判重,每一个maxid[j]所代表的字串一次跑一下字典树,最后字典树的节点个数就是所求的答案。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define N 1010char s[N], hz[N];void exkmp(char *s1, char *s2, int *next, int *ex) {    int i, j, p;    for (i = 0,j = 0,p = -1;s1[i] != '\0';i++,j++,p--) {        if (p == -1) {            j = 0;            do p++; while (s1[i+p] != '\0' && s1[i+p] == s2[j+p]);            ex[i] = p;        }        else if (next[j] < p) ex[i] = next[j];        else if (next[j] > p) ex[i] = p;        else {            j = 0;            while (s1[i+p] != '\0' && s1[i+p] == s2[j+p]) p++;            ex[i] = p;        }    }    ex[i] = 0;}int next[N],extand[N], mxid[N];struct Tr{    Tr *c[26];    Tr() {        for (int i = 0;i < 26;i++) c[i] = NULL;    }}*root;int cnt;void ins(int st, int len) {    int i, j;    Tr *p = root;    for (i = 0;i < len;i++) {        j = s[i+st]-'a';        if (p->c[j] == NULL) {            p->c[j] = new Tr();            cnt++;        }        p = p->c[j];    }}int main() {    int len, i, j;    while (~scanf("%s", s), s[0] != '#') {        len = strlen(s);        memset(mxid, 0, sizeof(mxid));        for (i = 1;i < len;i++) {            exkmp(s+i+1, s+i, next, next+1);            exkmp(s, s+i, next, extand);            for (j = 0;j < i;j++) {                mxid[j] = max(mxid[j], min(i-j, extand[j]));            }        }        root = new Tr();        cnt = 0;        for (i = 0;i < len;i++) {            ins(i, mxid[i]);        }        printf("%d\n", cnt);    }}


0 0