【多题合集】KMP练习
来源:互联网 发布:网络连接图标是灰色的 编辑:程序博客网 时间:2024/05/22 04:34
写在前面:太弱了,现在才开始做kmp← ←
传送门-P1961
题意:找出字符串中所有循环节次数大于1的前缀子串,输出它们的最小循环节长度与最大循环次数
思路:首先我们要学一门姿势
如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 ,
则说明字符串循环,而且 循环节长度为: i - next[i] 循环次数为: i / ( i - next[i] )
传送门-姿势及证明
接下来就比较简单了,预处理next数组,然后1-n找对应的前缀子串的循环节次数,大于1就输出答案(实际上就是next[i]>0,使循环节不是它本身)
#include<cstdio>#include<iostream>#include<cstring>using namespace std;int now,id,n,next[1000010];char s[1000010];main(){ scanf("%d",&n); while (n) { scanf("%s",s); printf("Test case #%d\n",++id); for (int i=1;i<n;i++) { now=next[i]; while (now&&s[now]!=s[i]) now=next[now]; next[i+1]=now+(s[now]==s[i]); } for (int i=1;i<=n;i++) if (next[i]&&i%(i-next[i])==0) printf("%d %d\n",i,i/(i-next[i])); puts(""); scanf("%d",&n); }}
传送门-P2406
题意:给定一个字符串,求它的最大循环次数
思路:比1961还简单,因为不用求非全串的子串,只用求全串,处理方法类似,只是次数为1的时候也要输出
代码:
#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>using namespace std;int now,l,next[1000010];char s[1000010];void work(){ if (s[0]=='.') exit(0); l=strlen(s); for (int i=1;i<l;i++) { now=next[i]; while (now&&s[now]!=s[i]) now=next[now]; next[i+1]=now+(s[i]==s[now]); } if (next[l]==0||l%(l-next[l])) printf("1\n"); else printf("%d\n",l/(l-next[l]));}main(){ while (scanf("%s",s)!=EOF) work();}
传送门-P2752
题意:给定一个字符串,求出它所有相同的前缀和后缀
思路:处理出next数组后,从next[len]输出,并当前指针跳到next[len],因为next[i]存的就是长度为i的串中前缀和后缀相等的最大值
代码:
#include<cstdio>#include<iostream>#include<cstring>using namespace std;char s[400010];int l,next[400010],ans[400010];void work(){ l=strlen(s); int now; for (int i=1;i<l;i++) { now=next[i]; while (now&&s[i]!=s[now]) now=next[now]; next[i+1]=now+(s[i]==s[now]); } ans[0]=0; ans[++ans[0]]=l; now=l; while (next[now]) ans[++ans[0]]=next[now],now=next[now]; for (int i=ans[0];i>=1;i--) printf("%d%c",ans[i]," \n"[i==1]);}main(){ while (scanf("%s",s)!=EOF) work();}
传送门-P3461
题意:给定两个字符串,找出第一个字符串在第二个字符串中出现次数
思路:用next数组进行字符串匹配,如果匹配成功,ans++,当前指针返回第一个字符串的最后一位
代码:
#include<cstdio>#include<iostream>#include<cstring>using namespace std;char ch[10010],s[1000010];int t,ans,l1,l2,next[10010];main(){ scanf("%d",&t); while (t--) { ans=0; scanf("%s%s",ch,s); l1=strlen(ch);l2=strlen(s); int now; for (int i=1;i<l1;i++) { now=next[now]; while (ch[i]!=ch[now]&&now) now=next[now]; next[i+1]=now+(ch[i]==ch[now]); } now=0; for (int i=0;i<l2;i++) { while (ch[now]!=s[i]&&now) now=next[now]; now+=(ch[now]==s[i]); if (now==l1) ans++,now=next[now]; } printf("%d\n",ans); }}
认真学习算法并尽力理解其本质,是学好OI的基础
1 0
- 【多题合集】KMP练习
- KMP 练习
- 基础练习KMP算法
- kmp练习 poj 2541
- kmp 练习下
- kmp练习poj3461
- kmp练习poj2752
- kmp练习poj2406
- kmp练习poj1961
- KMP练习(一)
- hdu 1711 KMP算法练习
- 【练习03】 KMP 1002 Oulipo
- 【练习03】 KMP 1004 Period
- 算法练习之KMP算法
- POJ 3461 Oulipo KMP练习
- 【编程练习】kmp算法代码
- KMP 顺序串操作练习
- KMP练习——KMP模式匹配 一(串)
- iOS开发者程序许可协议
- 开发自己的PHP MVC框架(二)
- js中数组(array)和对象(object)的区别
- iOS实时通讯之socket
- [MarsZ]ThinkPHP项目实战总结
- 【多题合集】KMP练习
- mybatis-实现关联表查询
- 次小生成树
- SQlite数据库的C编程接口(四) 绑定参数(Bound Parameters) ——《Using SQlite》读书笔记
- Java 线程池的原理与实现
- 【BZOJ2435】[Noi2011]道路修建【TreeDP】
- Ubuntu上的ftp配置连接
- Mysql导入官方示例employees问题解决记录
- 提供多个地图选择