HDU4763 - Theme Section(KMP)
题目描述
给定一个字符串S,要求你找到一个最长的子串,它既是S的前缀,也是S的后缀,并且在S的内部也出现过(非端点)
题解
CF原题不解释。。。。http://codeforces.com/problemset/problem/126/B
KMP的失配函数fail[i]的值就是s[0..i]的最长前缀且是后缀的长度~~~,因此我们从S的末尾位置开始沿着失配函数跑即可,对于当前fail[i],判断前缀s[0…i]是否在s[i+1..length(s)-i]是否出现即可~~~~如果存在则是最长子串的长度,否则继续判断长度为fail[fail[i]]的前缀是否符合上述情况,一直到找到就OK了。。。
一个多小时才看到此题~~~~~坑爹。。。。
代码:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; #define MAXN 1000005 char s[MAXN]; int f[MAXN]; void getfail(char *p,int len) { int j; f[0]=j=-1; for(int i=1; i<len; i++) { while(j>=0&&p[j+1]!=p[i]) j=f[j]; if(p[j+1]==p[i]) j++; f[i]=j; } } int find(int len) { int x=strlen(s); int j=-1; for(int i=len-1; i<x-len; i++) { while(j>=0&&s[j+1]!=s[i]) j=f[j]; if(s[j+1]==s[i]) j++; if(j+1==len) return len; } return -1; } int main() { int n; scanf("%d",&n); while(n--) { int pp=-1; scanf("%s",s); if(strlen(s)<3) printf("0\n"); else { getfail(s,strlen(s)); int j=strlen(s)-1; while(f[j]>=0) { if(f[j]+1>pp) { int t=find(f[j]+1); if(t>pp) { pp=t; break; } } j=f[j]; } if(pp!=-1) printf("%d\n",pp); else printf("0\n"); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步