2016——3——16 kmp 7题
来源:互联网 发布:拟线性偏好知乎 编辑:程序博客网 时间:2024/05/01 20:01
题目大意:找一个串在另一个串中出现的次数
题解:kmp(纯裸题)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define maxn 1000100 5 int n,fix,ans,i,lens,lent; 6 char s[maxn],t[maxn]; 7 int next[maxn]; 8 void getnext() 9 {10 fix=0;11 for (i=2; i<=lent; i++)12 {13 while(fix && t[fix+1]!=t[i]) fix=next[fix]; 14 if (t[fix+1]==t[i]) fix++;15 next[i]=fix;16 }17 }18 int KMP()19 {20 int count;21 fix=0; count=0;22 for (int i=1; i<=lens; i++)23 {24 while (fix && t[fix+1]!=s[i]) fix=next[fix];25 if (t[fix+1]==s[i]) fix++;26 if (fix==lent)27 {28 count++;29 fix=next[fix];30 } 31 }32 return count;33 }34 int main()35 {36 int z;37 scanf("%d",&z);38 for (int zz=1; zz<=z; zz++)39 {40 scanf("%s",t+1);41 scanf("%s",s+1);42 lens=strlen(s+1); 43 lent=strlen(t+1);44 memset(next,0,sizeof(next));45 getnext();46 ans=KMP();47 printf("%d\n",ans);48 }49 return 0;50 }
2、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2732
题目大意:给你一个字符串,让你求出最大重复周期(最大周期不和本身重合)
题解:kmp或者扩展kmp(但我并未用这种方法),我用的是kmp,但是一直WA,原来是求next数组把while写成了if(手抖毁一生)。
好吧,写题解了:用kmp求出next数组,然后在去递归next[n],因为j=next[next[n]]一直next下去直到其的next为0就ans+=n-j;
这就可以求出不和母串一样的最大重复周期,但是这又有一个问题你在求j时要递归时间就有可能为n^2的所以在每次递归时改变next的值就好了(详见代码);
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define inf 0x7ffffff 5 #define maxn 1000100 6 char s[maxn]; 7 int nnext[maxn]; 8 int n,i,j,fix; 9 long long ans;10 using namespace std;11 int main()12 {13 scanf("%d",&n);14 scanf("%s",s+1);15 fix=0;16 for (int i=2; i<=n; i++)17 {18 while (fix && s[fix+1]!=s[i]) fix=nnext[fix];19 if (s[fix+1]==s[i]) fix++;20 nnext[i]=fix;21 } 22 ans=0;23 for (int i=1; i<=n; i++)24 {25 int j=i;26 if (!nnext[j]) continue;27 while (nnext[nnext[j]]) nnext[j]=nnext[nnext[j]];28 ans+=(i-nnext[j]);29 }30 printf("%lld\n",ans);31 }
3、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2726
题目大意:给出一个字母组成的矩阵,找出一个最小的子矩阵,使得这个子矩阵的无限复制扩张之后的矩阵包含原来矩阵如:
ABABA
ABABA
他的最小重复子矩阵是AB
题解:还是kmp,只不过要有一点小技巧,就是把一行当作一个元素,那么就有n个元素,然后做kmp找重复子串,那么最小重复子串就为n-next[n],列也做此操作,答案就是
(n-r[n])*(m-c[m]);
1 #include <cstdio> 2 #include <cstring> 3 char s[10005][80], rs[80][10005]; 4 int R[10005], C[10005]; 5 int r, c; 6 7 void get_nextR() 8 { 9 R[0] = -1;10 int j = -1, i = 0;11 while(i < r)12 {13 if(j == -1 || strcmp(s[i], s[j]) == 0)14 {15 i++;16 j++;17 R[i] = j;18 }19 else20 j = R[j];21 } 22 } 23 24 void get_nextC() 25 { 26 C[0] = -1;27 int j = -1, i = 0;28 while(i < c)29 {30 if(j == -1 || strcmp(rs[i], rs[j]) == 0)31 {32 i++;33 j++;34 C[i] = j;35 }36 else37 j = C[j];38 } 39 } 40 41 int main()42 {43 while(scanf("%d %d", &r, &c) != EOF)44 {45 for(int i = 0; i < r; i++) 46 scanf("%s", s[i]);47 get_nextR();48 for(int i = 0; i < r; i++)49 for(int j = 0; j < c; j++)50 rs[j][i] = s[i][j];51 get_nextC();52 printf("%d\n", (r - R[r]) * (c - C[c]));53 }54 }
4、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2724
题目大意:给定一个字符串,要求找到同时是它前缀也是后缀的字符串的个数,并且输出他们的长度。
题解:理解一下next数组的用法,从next[n]一直往前求next,那么那些点的坐标就是answer。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define maxn 1000100 5 int n,ans,fix; 6 int nnext[maxn]; 7 char s[maxn]; 8 using namespace std; 9 void show(int n)10 {11 if (n<=0) return;12 show(nnext[n]);13 printf("%d ",n);14 }15 int main()16 {17 scanf("%d",&n);18 scanf("%s",s+1);19 fix=0;20 for (int i=2; i<=n; i++)21 {22 while (fix && s[fix+1]!=s[i]) fix=nnext[fix];23 if (s[fix+1]==s[i]) fix++;24 nnext[i]=fix;25 }26 show(n);27 return 0;28 }
5、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2723
题目大意:
现在给一个字符串A,和另一个字符串B。要你每次从B串中从左到右第第一个A串。
并且从B串中删除它,直到A串不为B串的子串。问需要几次删除操作。
题解:next数组的应用,只不过用一个堆记录那些没匹配成功的字符,在用它进行匹配。
1 #include<cstring> 2 #include<cstdio> 3 #include<cstring> 4 char t[1000100],s[1000100]; 5 int m,n,top,i,fix,ans; 6 int z[1000100],next[1000010],f[1000010]; 7 using namespace std; 8 int main() 9 {10 scanf("%s%s",t+1,s+1);11 m=strlen(s+1); n=strlen(t+1);12 for (fix=0,i=2; i<=n; i++)13 {14 while (fix && t[fix+1]!=t[i]) fix=next[fix];15 if (t[fix+1]==t[i]) fix++;16 next[i]=fix;17 }18 for (int i=1; i<=m; i++)19 {20 fix=f[z[top]];21 while (fix && t[fix+1]!=s[i]) fix=next[fix];22 if (t[fix+1]==s[i]) fix++;23 24 if (fix==n) top-=(n-1),ans++;25 else26 f[i]=fix, z[++top]=i;27 } 28 printf("%d\n",ans);29 }
6、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2719
题目大意:给出一个串S,它包含 N 个字符。设 Pi = S [ 1 .. I ] ,对于一些 Pi , 如果Pi能表示成K个字符串相连而成的(K > 1 ,且K尽量大),则打印I和K。
题解:如果i mod(i-next[i]) =0 && (i/(i-next[i])>1 输出答案(i);
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define inf 0x7fffffff 5 int n,ans; 6 int nnext[1000100]; 7 char s[1000100]; 8 using namespace std; 9 int main()10 {11 int z=0;12 while (true)13 {14 scanf("%d",&n);15 if (n==0) break;16 z++;17 printf("Test case #%d\n",z);18 scanf("%s",s+1);19 ans=0;20 int fix=0;21 for (int i=2; i<=n; i++)22 {23 while (fix && s[fix+1]!=s[i]) fix=nnext[fix];24 if (s[fix+1]==s[i]) fix++;25 nnext[i]=fix;26 }27 for (int i=2; i<=n; i++)28 {29 int k=i-nnext[i];30 if (i % k==0 && i/k>1) printf("%d %d\n",i,i/k);31 }32 printf("\n");33 }34 }
7、传送门:http://begin.lydsy.com/JudgeOnline/problem.php?id=2720
题目大意:给你一个字符串,它是由某个字符串不断自我连接形成的。 但是这个字符串是不确定的,现在只想知道它的最短长度是多少.
题解:同上;
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define inf 0x7fffffff 5 int n,ans; 6 int nnext[1000100]; 7 char s[1000100]; 8 using namespace std; 9 int main()10 {11 scanf("%d",&n);12 scanf("%s",s+1);13 ans=0;14 int fix=0;15 for (int i=2; i<=n; i++)16 {17 while (fix && s[fix+1]!=s[i]) fix=nnext[fix];18 if (s[fix+1]==s[i]) fix++;19 nnext[i]=fix;20 }21 printf("%d\n",n-nnext[n]);22 }
- 2016——3——16 kmp 7题
- KMP——Period
- KMP——总结
- 字符串——KMP
- bzoj1355——KMP
- 算法——KMP
- POJ2406——KMP
- KMP——转载
- KMP——理论知识
- KMP算法—转
- poj3461—KMP裸题
- 算法导论—KMP
- 数据结构—KMP模板
- KMP—介绍
- 2016夏季练习——KMP
- 2016夏季练习——KMP
- 2016夏季练习——KMP
- 2016夏季练习——KMP
- 转自他人——————TLE之前,没有一个节点叫失败!!!
- KMP之我见
- poj 3641 ——2016——3——15
- bzoj1355——2016——3——15
- bzoj3942——2016——3——15
- 2016——3——16 kmp 7题
- 编译fdk-aac for ios
- 几种哈希算法原理(转发)
- begin lydsy 2731
- Zju1290 Word-Search Wonder(http://begin.lydsy.com/JudgeOnline/problem.php?id=2768)
- 这些时间投,更容易被HR“翻牌子”!
- 关键词匹配(Ac自动机模板题)
- BufferKnife及插件使用
- 利用 ajax 像后台传递数组