HDU 4763:Theme Section(KMP)

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

Theme Section

Problem Description
 
It's time for music! A lot of popular musicians are invited to join us in the music festival. Each of them will play one of their representative songs. To make the programs more interesting and challenging, the hosts are going to add some constraints to the rhythm of the songs, i.e., each song is required to have a 'theme section'. The theme section shall be played at the beginning, the middle, and the end of each song. More specifically, given a theme section E, the song will be in the format of 'EAEBE', where section A and section B could have arbitrary number of notes. Note that there are 26 types of notes, denoted by lower case letters 'a' - 'z'.
To get well prepared for the festival, the hosts want to know the maximum possible length of the theme section of each song. Can you help us?
 
Input
 
The integer N in the first line denotes the total number of songs in the festival. Each of the following N lines consists of one string, indicating the notes of the i-th (1 <= i <= N) song. The length of the string will not exceed 10^6.
Output
 
There will be N lines in the output, where the i-th line denotes the maximum possible length of the theme section of the i-th song.
 
Sample Input
 
5
xy
abc
aaa
aaaaba
aaxoaaaaa
 
Sample Output
0
0
1
1
2
 
题意:一条串可以分成前中后三个部分,求三个部分最长的相同子串的长度。
思路:做了好久的KMP一直只会模板题,坚持不看题解,终于花了半天时间搞出这道偏水的题目,主要在于 中间的部分 的定义,该串不包含前面,也不包含后面的部分就是中间,理解错题意瞎搞了好久。我的做法是先劈成三部分,然后先对前后用kmp算最长的公共前后缀长度,然后再把前后缀部分保留,其他全部给中间部分,然后分别再对前面和中间,后面和中间用kmp算出最长的公共子串长度,然后取较小者即可。算是一个比较暴力无脑的做法吧= =。
 
 
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <string>
  6 using namespace std;
  7 #define N 1000005
  8 string s;
  9 string le, ri, mi, temp;
 10 int nxt[N];
 11 
 12 void make_next(string s)
 13 {
 14     memset(nxt, 0, sizeof(nxt));
 15     int l = s.size();
 16     int j = -1, i = 0;
 17     nxt[0] = -1;
 18     while(i < l) {
 19         if(j == -1 || s[j] == s[i]) {
 20             j++; i++;
 21             nxt[i] = j;
 22         } else {
 23             j = nxt[j];
 24         }
 25     }
 26 }
 27 /*
 28 前面的串和后面的串匹配的时候只能前后缀匹配传入0
 29 前面的串和中间的串匹配或者后面的串和中间的串匹配传入1
 30 */
 31 int kmp(string s, string str, int flag)
 32 {
 33     int l = s.size(), L  = str.size();
 34     make_next(s);
 35     int i = 0, j = 0;
 36     while(i < L && j < l) {
 37         if(j == -1 || s[j] == str[i]) {
 38             i++; j++;
 39             if(flag && j==l) return j;
 40         } else {
 41             j = nxt[j];
 42         }
 43     }
 44     if(i == L) return j;
 45     return 0;
 46 }
 47 
 48 int main()
 49 {
 50     int t;
 51     cin >> t;
 52     while(t--) {
 53         s.clear();
 54         temp.clear();
 55         mi.clear();
 56         le.clear();
 57         ri.clear();
 58         cin >> s;
 59         int len = s.size();
 60         if(len < 3) {
 61             puts("0"); continue;
 62         }
 63         for(int i = 0; i < len; i++) {
 64             if(i <= len/3 - 1) {
 65                 le += s[i];
 66             } else if(i >= len*2/3) {
 67                 ri += s[i];
 68             } else {
 69                 mi += s[i];
 70             }
 71         }//将一条串拆成三部分
 72 
 73         int lo = kmp(le, ri, 0);
 74         if(lo == 0) {
 75             puts("0"); continue;
 76         }
 77         //lo是公共前后缀长度
 78 //        }
 79         for(int i = 0; i < ri.size()-lo; i++)
 80             mi += ri[i];
 81 
 82         for(int i = lo; i < le.size(); i++) {
 83             temp += le[i];
 84         }
 85 
 86         int l = le.size(), r = ri.size();
 87 
 88         ri.erase(0, r - lo);
 89         le.erase(lo, r);
 90         temp += mi;
 91 
 92         int ans = 0;
 93         int k = kmp(le, temp, 1);
 94         int g = kmp(ri, temp, 1);
 95         ans = min(k, g);
 96 
 97         cout << ans << endl;
 98     }
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/fightfordream/p/5697460.html