【多题合集】KMP练习
2016-03-29 11:20
218 查看
写在前面:太弱了,现在才开始做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,使循环节不是它本身)
传送门-P2406
题意:给定一个字符串,求它的最大循环次数
思路:比1961还简单,因为不用求非全串的子串,只用求全串,处理方法类似,只是次数为1的时候也要输出
代码:
传送门-P2752
题意:给定一个字符串,求出它所有相同的前缀和后缀
思路:处理出next数组后,从next[len]输出,并当前指针跳到next[len],因为next[i]存的就是长度为i的串中前缀和后缀相等的最大值
代码:
传送门-P3461
题意:给定两个字符串,找出第一个字符串在第二个字符串中出现次数
思路:用next数组进行字符串匹配,如果匹配成功,ans++,当前指针返回第一个字符串的最后一位
代码:
认真学习算法并尽力理解其本质,是学好OI的基础
传送门-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的基础
相关文章推荐
- Opengl坐标系 坐标变换 笔记
- Hibernate 注解和配置文件两种方法的对比(有实例)
- 模块管理常规功能自己定义系统的设计与实现(52--功能更新[2] 对百分比字段的操作)
- Jgroups环境检测
- 用Winrar批量解压缩有密码文件方法,只需输入一次密码
- 2016年3月28日作业 沟通和合同管理
- StringBuffer跟StringBuilder的区别
- linux内核串口控制器注册以及收发
- 【bzoj1565】【NOI2009】【植物大战僵尸】【拓扑排序+最小割】
- Android 中Webview 自适应屏幕
- leetcode 91. Decode Ways
- win7各种无法上网的解决办法
- 开发自己的PHP MVC框架(二)
- js中数组(array)和对象(object)的区别
- Android开发IDE插件集合----selector
- iOS开发者程序许可协议
- 程序员编写技术文档的新手指南
- [ubuntu]deb软件源
- mongodb进阶三之mongodb管理
- css3属性整理