1. 程式人生 > >CODEVS——T 1404 字符串匹配

CODEVS——T 1404 字符串匹配

font esp cti log 下標 fault left names csdn

http://codevs.cn/problem/1404/

時間限制: 1 s 空間限制: 128000 KB 題目等級 : 大師 Master 題目描述 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

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 字符串匹配