HDU 4763 - Theme Section(KMP)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4763 - Theme Section(KMP)相关的知识,希望对你有一定的参考价值。

题目链接:

      http://acm.hdu.edu.cn/showproblem.php?pid=4763

题目描述:

  现有一字符串S,要求在S中找到最长的子串E,使得S满足格式“EAEBE”,其中A,B可以为任意的S子串。也就是说子串E既是S的前缀也是S的后缀,同时还在S中间出现,但不与前缀E与后缀E重叠。

解题思路:

  学习KMP的第一道题。KMP的详解这篇文章写得很好:http://www.cnblogs.com/c-cloud/p/3224788.html,看完应该能理解前缀后缀概念和next数组的意义了(顺便给自己备忘下)。

  好,那么有了上述储备知识后就可以来解题啦。已知next[i]表示的是字符串str中的一段,即“str[0]str[1] ... str[i-1]str[i]”这个字符串,的相同前后缀的最长长度,那么要在字符串S中找E,就直接从S的末位开始,假设k = next[S.length()-1],那么也就是说存在前缀“S[0]S[1] ... S[k-1]”与后缀“S[S.length()-k] ... S[S.length()-1]”相等,那么直接在S的子串“S[k]S[k+1] ... S[S.length()-k-1]”中寻找那段前缀就可以了。如果没有的话就减小前后缀长度重新在新中间段中寻找即可。

  嘛,说的不是很清楚,仅供参考用...

代码:

 1 //#include <iostream>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 //#include <vector>
 6 //#include <algorithm>//C++中限定字符有next,用C++的库的话oj会对next报错
 7 using namespace std;
 8 
 9 #define ll long long
10 #define INF 0x3f3f3f3f3f
11 #define MAX 1001000
12 
13 char T[MAX], S[MAX];
14 int next[MAX];
15 
16 /*void display(int n)
17 {
18     for(int i = 0; i < n; ++i) {
19         printf("%d ", next[i]);
20     }
21     printf("\\n");
22 }*/
23 
24 void getNext()
25 {
26     next[0] = 0;
27     int len = strlen(T);
28     int k = 0;
29     for(int i = 1; i < len; ++i) {
30         while(k > 0 && T[i] != T[k])
31             k = next[k-1];
32         if(T[i] == T[k])
33             k++;
34         next[i] = k;
35     }
36 }
37 
38 int main()
39 {
40     //freopen("debug\\\\in.txt", "r", stdin);
41     //freopen("CON", "w", stdout);
42     int i, j, k;
43     int test;
44     scanf("%d", &test);
45     while(test--) {
46         scanf("%s", T);
47         memset(next, 0, sizeof(next));
48         getNext();
49         int len = strlen(T);
50         //display(len);
51 
52         int ans = 0;
53         j = next[len - 1]; //获取整个字符串的最长相同前后缀长度
54         bool flag = 0; //flag=1时表明找到题目要求的字符串了,跳出循环
55         for(i = j; i >= 0; --i) { //从最长相同前后缀长度开始递减
56             k = len - i - 1; //中间段的下界,同时也是搜寻下标
57             while(next[k] == 0 && k >= 2 * i - 1) //寻找中间段最右边next值不为0的字符
58                 k--;
59             while(k >= i * 2 - 1) { //明显中间的子串不能跟前缀重叠
60                 if(next[k] >= i) { //找到子串了
61                     ans = i;
62                     flag = 1;
63                     break;
64                 }
65                 else
66                     k = next[k] - 1; //否则向前继续寻找
67             }
68             if(flag) break;
69         }
70         printf("%d\\n", ans);
71     }
72 }

 

以上是关于HDU 4763 - Theme Section(KMP)的主要内容,如果未能解决你的问题,请参考以下文章

hdu4763 Theme Section

hdu4763Theme Section

HDU 4763 - Theme Section(KMP)

HDU4763-Theme Section(KMP+二分)

HDU-4763 Theme Section KMP

Theme Section HDU - 4763(些许暴力)