Codeforces Round #282 (Div. 1) B. Obsessive String
题目:链接
解题思路:
- 先用kmp找到所有的匹配点,时间复杂度O(n+m),n和m分别是文本和模版字符串的长度。
- 用dp[i]表示i是bk(题中的)时,字符串前i个字符的子串中的满足条件的总数
- 定义dp2[i]是前i个dp[i]的和,dp3[i]是前i个dp2[i]的和,m是匹配串的长度。
- 转移:当i不是匹配的结尾点时,dp[i]=dp[i-1],反之,dp[i]=dp3[i]+i-m+1;
- 当i不是匹配的结尾点时,只要把bk从i-1点变到i点,故数量不变,dp[i]=dp[i-1]。
- 而当i是匹配的结尾点时,考虑ak(题中)可以取1,2,..,i-m+1(index从1开始)
- 故当k=1时,有i+m-1个(当时就由于没考虑到k=1的情况要单独算,一直过不了样例)
- 当k大于1时,当ak取j(1<=j<=i-m+1)时,bk-1可以取1,2,...,j-1,故有dp2[j-1]
- 而由ak取值,故有dp3[i-m]个,故dp[i]=dp3[i]+i-m+1
- 最后的结果就是dp2[n-1],n为字符串长度。
- 注意取模
- 同时解题思路index是从1开始,我程序中index从0开始
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=100010; 7 const int mod=1e9+7; 8 char s[maxn]; 9 char t[maxn]; 10 int f[maxn]; 11 int dp[maxn]; 12 int q[maxn]; 13 int dp2[maxn]; 14 int dp3[maxn]; 15 void getFail(char *P, int *f) 16 { 17 int m=strlen(P); 18 f[0]=0; 19 f[1]=0; 20 for(int i=1;i<m;i++) 21 { 22 int j=f[i]; 23 while(j&&P[i]!=P[j]) 24 { 25 j=f[j]; 26 } 27 f[i+1]=P[i]==P[j]?j+1:0; 28 } 29 } 30 void find(char *T,char *P,int *f) 31 { 32 int n=strlen(T); 33 int m=strlen(P); 34 getFail(P,f); 35 int j=0; 36 for(int i=0;i<n;i++) 37 { 38 while(j&&P[j]!=T[i]) 39 { 40 j=f[j]; 41 } 42 if(P[j]==T[i]) 43 { 44 j++; 45 } 46 if(j==m) 47 { 48 q[i]=1; 49 } 50 } 51 } 52 53 54 int main() 55 { 56 while(scanf("%s%s",s,t)!=EOF) 57 { 58 int i; 59 memset(q,0,sizeof(q)); 60 find(s,t,f); 61 int n=strlen(s); 62 int m=strlen(t); 63 dp[0]=dp2[0]=dp3[0]=q[0]; 64 for(i=1;i<=n;i++) 65 { 66 if(q[i]==0) 67 { 68 dp[i]=dp[i-1]; 69 } 70 else 71 { 72 dp[i]=(dp3[i-m]+i-m+2)%mod; 73 } 74 dp2[i]=(dp[i]+dp2[i-1])%mod; 75 dp3[i]=(dp2[i]+dp3[i-1])%mod; 76 } 77 printf("%d\n",dp2[n-1]); 78 } 79 80 81 82 return 0; 83 }
AC如下: