1. 程式人生 > >【BZOJ 3620】 3620: 似乎在夢中見過的樣子 (KMP)

【BZOJ 3620】 3620: 似乎在夢中見過的樣子 (KMP)

【分析】

  做這題的時候並不知道資瓷N^2的KMP。。。

  其實N^2的KMP還挺容易打錯的,因為根節點不能是0,是st-1。中間有幾個判斷都要注意。

  直接列舉起點。然後做一遍KMP。

  詢問的時候看看nt是否符合。首先要長於k,其次不能相交且要空出一個位置。

  假設前後綴匹配部分長度是p,列舉到右端點為j。

  則2*p<j-i+1,p>=k

  p一開始是nt,然後一直nt。但是這樣暴就O(n^3)了會超時的。

  用一個g陣列記錄,他到他的nt中,p大於等於k的最小值即可。

 1 #include<cstdio>
 2 #include<cstdlib>
 3
#include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 15010 8 #define INF 0xfffffff 9 10 char s[Maxn]; 11 int l,k,nt[Maxn],g[Maxn]; 12 13 void KMP(int st) 14 { 15 nt[st]=st-1;g[st-1]=INF; 16 g[st]=k==1?1:INF; 17 for(int p=st-1
,i=st+1;i<=l;i++) 18 { 19 while(s[i]!=s[p+1]&&p>=st) p=nt[p]; 20 if(s[i]==s[p+1]) p++; 21 nt[i]=p; 22 g[i]=INF; 23 if(i-st+1>=k) g[i]=i-st+1; 24 g[i]=min(g[i],g[nt[i]]); 25 } 26 } 27 28 int ans=0; 29 void ffind(int st) 30 { 31 KMP(st);
32 for(int i=st;i<=l;i++) 33 { 34 if(2*g[nt[i]]<i-st+1) ans++; 35 } 36 } 37 38 int main() 39 { 40 scanf("%s",s+1);l=strlen(s+1); 41 scanf("%d",&k); 42 for(int i=1;i<=l;i++) ffind(i); 43 printf("%d\n",ans); 44 return 0; 45 }
View Code

2017-04-25 11:48:23