https://www.nowcoder.com/acm/contest/147/F
即做4个kmp,可持久化每增加一个字符后的match。
题外话:假如说在a串中找b串,做kmp的过程其实在不断的使b串的前缀与当前匹配到的串的后缀对齐,扫a串,每增加一个字符就更新一次match(最大匹配位置),当match为b串长度-1时,即找到了b串,更新操作均摊下来为O(1)。注意b串为ccccccccccc的情况,匹配失败,每次只会往前跳一个字符,在本题中就会成为卡时间的地方,优化加一行代码即可,见代码。
#include <cstdio> #include <cstring> #include <cctype> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <set> using namespace std; typedef long long ll; int kmp_fail[4][100005]; char kmp_p[4][100005]; void getFail(char *P, int *fail) { int match = -1; fail[0] = -1; for (int i = 1; P[i]; ++i) { while (match >= 0 && P[match + 1] != P[i]) { match = fail[match]; } if (P[match + 1] == P[i]) { match++; } fail[i] = match; if(match!=-1&&P[i+1]==P[match+1]) fail[i] = fail[match]; //优化:两者相等,那么i+1失配时,match+1也会失配,则可跳过 } } char s[100005]; int main() { int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%s",kmp_p[i]); getFail(kmp_p[i], kmp_fail[i]); } vector<int>vt[5]; scanf("%s",s); int match[4]={-1,-1,-1,-1}; int len[4]; int mm=100000000; for(int i=0;i<n;i++) {len[i]=strlen(kmp_p[i]);mm=min(mm,len[i]);} printf("%d ",mm); for(int i=0;s[i];i++) { int mi=100000000; if(s[i]=='-') { for(int j=0;j<n;j++) { if(vt[j].size()>0) {vt[j].pop_back(); if(vt[j].size()>0) match[j]=vt[j][vt[j].size()-1]; else match[j]=-1; } } if(vt[4].size()>0) { vt[4].pop_back(); if(vt[4].size()>0) printf("%d ",vt[4][vt[4].size()-1]); else printf("%d ",mm); } else printf("%d ",mm); } else { for(int j=0;j<n;j++) { while(match[j]>=0&&kmp_p[j][match[j]+1]!=s[i]) match[j]=kmp_fail[j][match[j]]; if(kmp_p[j][match[j]+1]==s[i]) match[j]++; mi=min(mi,len[j]-match[j]-1); vt[j].push_back(match[j]); } vt[4].push_back(mi); printf("%d ",mi); } } return 0; }