CodeVS1404 字符串匹配(扩展kmp)
2016-07-31 14:34
288 查看
CodeVS1404 字符串匹配 扩展kmp讲解
题目描述 Description给你两个串A,B,可以得到从A的任意位开始的子串和B匹配的长度。
给定K个询问,对于每个询问给定一个x,求出匹配长度恰为x的位置有多少个。
N,M,K<=200000
输入描述 Input Description
第一行三个数 N,M,K,表示A的长度、B的长度和询问数。
第二行为串A。
第三行为串B。
接下来K行,每行1个数X。
输出描述 Output Description
对于每个询问输出一个数。
样例输入 Sample Input
6 2 2
aabcde
ab
0
2
样例输出 Sample Output
4
1
数据范围及提示 Data Size & Hint
各个测试点1s
分析
假如有匹配串A长度为N,模式串B长度为M,那么扩展KMP算法可以在O(N+M)的时间内算出对于A的每一个位置,与B的最长匹配长度是多少(即与B串前缀重合的最长长度),算法如下:PART_1 初始化next数组
设next[i]表示B串的i位置开始的字符串与B串的前缀的最长重合长度(注意这里与KMP中的next是不一样的)。明显地,next[1]=M(我的字符串的下标习惯从1开始),next[2]也可以用一个简单的for循环求出,pos初始化为2;当i∈[3,M]时,我首先认为关于1~i-1的信息已全部求出,我们记录一个pos,它的意义是当前已计算出的next数组中,j+next[j]-1能达到的最右端所对应的i,这个不太好理解,可以参考manacher算法的思想戳这(其实manacher和扩展kmp是很像的),令rp=pos+next[pos]-1(1)当i+next[i-pos+1]<rp时,易得next[i]=next[i-pos+1]
(2)当i+next[i-pos+1]>=rp时,rp后的元素,即b[rp+j],可能会和b[rp-i+1+j]相等,这时进行暴力扩展,如果扩展发生,则更新pos为i,next[i]直接在扩展中求出。
注意:有时rp可能小于i,这时可以加一特判,直接进行暴力求
PART_2 匹配
令ans[i]表示a串中以a[i]为开头的后缀和b串的最长匹配长度,设pos表示a串中对于所有的i,i+ans[i]-1能达到的最远位置对应的i,rp就是pos+ans[pos]-1,next[1]暴力求出,pos初始化为1;当i∈[2,N]时:(1)若i+next[i-pos+1]-1<rp,则ans[i]=next[i-pos+1]
(2)若i+next[i-pos+1]-1>=rp,则进行暴力扩展,同时更新pos,ans在扩展时求出
注意:如果rp<i,那么加一特判,直接暴力扫描
代码
//CodeVS1404 字符串匹配 扩展KMP #include <cstdio> #include <cstring> #include <algorithm> #define maxlen 200010 using namespace std; char a[maxlen], b[maxlen]; int next[maxlen], N, M, K, cnt[maxlen], ans[maxlen], tong[maxlen]; void init() { int i, j, p, a; next[1]=M; for(i=1;b[i]==b[i+1];i++); next[2]=i-1; a=2; for(i=3;i<=M;i++) { p=a+next[a]-1; if(i+next[i-a+1]-1>=p) { if(p<i) { for(j=i;b[j]==b[j-i+1];j++);j--; if(b[j]==b[j-i+1]&&j>=i)next[i]=j-i+1; } else { for(j=1;b[p+j]==b[p-i+1+j];j++); next[i]=p-i+j; } if(i+next[i]-1>p)a=i; } else next[i]=next[i-a+1]; } } void exkmp() { int i, j, rp, pos; for(i=1;i<=min(N,M)&&a[i]==b[i];i++);i--; ans[1]=i; tong[i]++; pos=1; for(i=2;i<=N;i++) { rp=pos+ans[pos]-1; if(i+next[i-pos+1]-1>=rp) { if(rp<i) { for(j=i;a[j]==b[j-i+1];j++);j--; if(a[j]==b[j-i+1]&&j>=i)ans[i]=j-i+1; } else { for(j=rp+1;a[j]==b[j-i+1];j++);j--; ans[i]=j-i+1; } } else ans[i]=next[i-pos+1]; if(i+ans[i]-1>rp)pos=i; tong[ans[i]]++; } } int main() { int q; scanf("%d%d%d",&N,&M,&K); scanf("%s%s",a+1,b+1); init(); exkmp(); while(K--) { scanf("%d",&q); printf("%d\n",tong[q]); } return 0; }
相关文章推荐
- Codevs 1404 字符串匹配(Kmp)
- 字符串匹配 扩展KMP BM&Sunday
- 字符串匹配-扩展KMP
- 字符串匹配—KMP 扩展KMP Manacher
- 字符串匹配--扩展KMP模板
- codevs1404字符串匹配
- 【codevs1404】字符串匹配 KMP
- <kmp>codevs 1404 字符串匹配
- SDJZU_新生_字符串匹配(KMP)_A - Number Sequence
- [复习]KMP 字符串匹配
- 字符串匹配(普通+KMP)
- 算法模板——KMP字符串匹配
- KMP字符串匹配算法——用最容易理解的方式描述
- kmp(字符串匹配)
- 字符串匹配算法KMP详解
- 每周一算法之六——KMP字符串匹配算法
- 算法——字符串匹配之KMP——看不懂算我输
- KMP(字符串匹配)
- 字符串匹配之朴素算法和通配符扩展
- P3375 【模板】KMP字符串匹配