KMP专题

1、【HDU 3336Count the string(KMP+dp)

题意:求给定字符串含前缀的数量,如输入字符串abab,前缀是aababaabab,在原字符串中出现的次数分别是2211,所以答案是2+2+1+1=6.

解题思路:s[]=abcdabcdabcdea ==> f[] = 00001234567801f[i]=k的含义是s[i-k]=s[i]dp[i]=dp[f[i]]+1dp[i]表示以s[i]结尾的前缀的数量

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 using namespace std;
 7 #define ll __int64
 8 const int N=2*1e5+10;
 9 const ll mod=10007;
10 char p[N]; 
11 ll f[N], ans[N];
12 int lenp;
13 void getf()
14 {
15     memset(f, 0, sizeof(f));
16     int i,j;
17     j=f[1]=0;
18     i=1;
19     while(i<lenp)
20     {
21         while(0!=j && p[i+1]!=p[j+1]) j=f[j];
22         if(p[i+1] == p[j+1]) j++;
23         f[++i] = j;
24     }
25 }
26 int main(){
27     int t;
28     scanf("%d", &t);
29     while(t--){
30         memset(ans, 0, sizeof(ans));
31         memset(p, '\0', sizeof(p));
32         scanf("%d%s", &lenp, p+1);
33         getf();
34         ll sum=0;
35         for(int i=1; i<=lenp; i++) ans[i] = (ans[f[i]]+1)%mod;
36         for(int i=1; i<=lenp; i++) sum = (sum+ans[i])%mod;
37         printf("%I64d\n", sum);
38 //        for(int i=1; i<=lenp; i++) cout<<f[i];
39 //\        cout<<endl; 
40     }
41     return 0;
42 }
View Code

2、【POJ 2406Power Strings

题意:如果字符串a=”abc”,字符串b=”def”,那么a*b=”abcdef”,输入字符串s,那么s=x^nn的最大值。

解题思路:n的最大值也就是求s的最小循环节【s[]=abcdabcdabcdea ==> f[] = 00001234567801,最小循环节只能是len-f[len]】然后判断len是否能整除最小循环节,如果不能整除,那么n最大值只能是1

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 using namespace std;
 7 const int N=1000005;
 8 char s[N];
 9 int f[N], lens;
10 void getf(){
11     memset(f, 0, sizeof(f));
12     int i, j;
13     j=f[0]=-1;
14     i=0;
15     while(i<lens){
16         while(j!=-1 && s[i+1]!=s[j+1]) j = f[j];
17         f[++i] = ++j;
18     }
19 }
20 int main(){
21     while(~scanf("%s", s)){
22         lens = strlen(s);
23         if(lens==1 && s[0]=='.') break;
24         getf();
25         f[lens-1]++;
26         int ans = lens-f[lens-1];
27         if(lens%ans==0) ans = lens/ans;
28         else ans=1;
29         printf("%d\n", ans);
30     
31     }
32     return 0;
33 }
View Code

3、【HDU 1867A + B for you again

题意:输入两个字符串(len<=1e5)ABs1=A+B【去掉了A的后缀跟B的前缀相等部分】,s2=B+A【去掉了B的后缀跟A的前缀相等部分】,输出s1s2其中一个,先考虑长度小的,长度差相等的时候考虑字典序小的。

解题思路:关键是求出A的后缀与B的前缀以及B的后缀跟A的前缀重叠部分的长度。A的后缀跟B的前缀重叠部分的求法:求出Bfp[],拿B去匹配A,如果能一直匹配到最后一位,那么重叠部分就是B已经匹配了的长度。

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 using namespace std;
 7 const int N=1e5+10;
 8 char s[N], p[N];
 9 int fs[N], fp[N], lens, lenp;
10 void kmp_getfs(){
11     memset(fs, 0, sizeof(fs));
12     int i, j;
13     i=2, j=fs[1]=0;
14     while(i<=lens){
15         while(j!=0 && s[i]!=s[j+1]) j = fs[j];
16         if(s[i] == s[j+1]) j++;
17         fs[i++]=j;
18     }
19 }
20 void kmp_getfp(){
21     memset(fp, 0, sizeof(fp));
22     int i, j;
23     i=2, j=fp[1]=0;
24     while(i<=lenp){
25         while(j!=0 && p[i]!=p[j+1]) j=fp[j];
26         if(p[i] == p[j+1]) j++;
27         fp[i++] = j;
28     }
29 }
30 int main(){
31     while(~scanf("%s%s", s+1, p+1)){
32         lens = strlen(s+1);
33         lenp = strlen(p+1);
34         kmp_getfs();
35         kmp_getfp();
36         int is=1, jp=0, flags=0;
37         for(is=1; is<=lens; is++){
38             while(jp!=0 && s[is]!=p[jp+1]) jp=fp[jp];
39             if(s[is]==p[jp+1]){
40                 jp++;
41                 if(is==lens) flags=1;
42             }
43         }
44         int ip=1, js=0, flagp=0;
45         for(ip=1; ip<=lenp; ip++){
46             while(js!=0 && p[ip]!=s[js+1]) js = fs[js];
47             if(p[ip] == s[js+1]){
48                 js++;
49                 if(ip==lenp) flagp=1;
50             }
51         }
52         int sums=lens+lenp-jp;
53         int sump=lens+lenp-js;
54         if(sums==sump){
55             string sp, ps;
56             sp.clear(), ps.clear();
57             for(int i=1; i<=lens; i++) sp+=s[i];
58             for(int i=jp+1; i<=lenp; i++) sp+=p[i];
59             for(int i=1; i<=lenp; i++) ps+=p[i];
60             for(int i=js+1; i<=lens; i++) ps+=s[i];
61             if(sp>ps) cout<<ps<<endl;
62             else cout<<sp<<endl;
63         }
64         else if(sums>sump){
65             printf("%s", p+1);
66             for(int i=js+1; i<=lens; i++) cout<<s[i];
67             cout<<endl;
68         }
69         else if(sums<sump){
70             printf("%s", s+1);
71             for(int i=jp+1; i<=lenp; i++) cout<<p[i];
72             cout<<endl;
73         }
74     }
75     return 0;
76 } 
View Code

 

posted @ 2016-05-06 21:51  穿破石  阅读(120)  评论(0编辑  收藏  举报