【KMP】BZOJ3942-[Usaco2015 Feb] Censoring
【题目大意】
有一个S串和一个T串,长度均小于1,000,000,设当前串为U串,然后从前往后枚举S串一个字符一个字符往U串里添加,若U串后缀为T,则去掉这个后缀继续流程。输出最后的S串。
【思路】
三天前写过一次,用的是以前的KMP模板,但是觉得太乱了,数组下标一会儿是下标一会儿是长度,傻傻分不清。参照其他人常见的方法重改了一发,算是比较清晰的KMP了,所有数组下标均直接指代字符串下标。
维护两个同进同出的栈,s代表当前的U串,a代表在s串种相应位置时的j指针位于模式串中的下标。每次将匹配串的下一位压入s中,用KMP判断匹配。一旦成功匹配到一个,便从栈中弹出即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=1000000+50; 7 char p[MAXN],t[MAXN],s[MAXN]; 8 int next[MAXN],a[MAXN],len,lenp; 9 10 void getnext() 11 { 12 int i=0,j=-1; 13 next[i]=j; 14 for (int i=1;i<len;i++) 15 { 16 while (j!=-1 && p[i]!=p[j+1]) j=next[j]; 17 if (p[i]==p[j+1]) ++j; 18 next[i]=j; 19 } 20 } 21 22 void solve() 23 { 24 int top=0; 25 for (int i=0;i<len;i++) 26 { 27 int j=a[top]; 28 s[++top]=t[i]; 29 while (j!=-1 && p[j+1]!=s[top]) j=next[j]; 30 if (p[j+1]==s[top]) ++j; 31 a[top]=j; 32 if (a[top]==lenp-1) top-=lenp; 33 } 34 s[top+1]='\0'; 35 puts(s+1); 36 } 37 38 int main() 39 { 40 scanf("%s%s",t,p); 41 len=strlen(t),lenp=strlen(p); 42 getnext(); 43 solve(); 44 return 0; 45 }