CODEVS——T 1404 字符串匹配
http://codevs.cn/problem/1404/
時間限制: 1 s 空間限制: 128000 KB 題目等級 : 大師 Master 題目描述 Description給你兩個串A,B,可以得到從A的任意位開始的子串和B匹配的長度。
給定K個詢問,對於每個詢問給定一個x,求出匹配長度恰為x的位置有多少個。
N,M,K<=200000
第一行三個數 N,M,K,表示A的長度、B的長度和詢問數。
第二行為串A。
第三行為串B。
對於每個詢問輸出一個數。
樣例輸入 Sample Input6 2 2
aabcde
ab
0
2
4
1
各個測試點1s
exkmp~~~ctrl_c+ctrl_v
假如有匹配串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,那麽加一特判,直接暴力掃描
這個題就明了了~~~
1 #include <algorithm> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int N(200000+5); 8 int n,m,k,lb,la; 9 int p[N],ans[N]; 10 char a[N],b[N]; 11 12 inline void Get_next() 13 { 14 for(int i=2,j=0;i<=lb;p[i++]=j) 15 { 16 for(;b[i]!=b[j+1]&&j>0;) j=p[j]; 17 if(b[i]==b[j+1]) j++; 18 } 19 } 20 inline void kmp() 21 { 22 for(int i=1,j=0;i<=la;i++) 23 { 24 for(;a[i]!=b[j+1]&&j>0;) j=p[j]; 25 if(a[i]==b[j+1]) j++; 26 ans[j]++; 27 } 28 } 29 30 int main() 31 { 32 scanf("%d%d%d%s%s",&n,&m,&k,a+1,b+1); 33 la=strlen(a+1); lb=strlen(b+1); 34 Get_next(); kmp(); 35 for(int i=lb;i>0;i--) ans[p[i]]+=ans[i]; 36 for(int i=0;i<lb;i++) ans[i]-=ans[i+1]; 37 for(int pos;k--;) 38 { 39 scanf("%d",&pos); 40 printf("%d\n",ans[pos]); 41 } 42 return 0; 43 }
CODEVS——T 1404 字符串匹配