KMP算法复习总结:Bzoj3620&&Bzoj3670
2016-03-16 07:51
302 查看
自从NOIP考完已经4个月没有写KMP了,最近考试考到了字符串相关题目才让我重新想起这个算法
事实证明我已经不会辣QAQ
趁早复习一下省的考到的时候挂了……
KMP算法就是一个next数组,记录的是一系列位置,表示当前串失配后返回一个有最长公共前缀的点,注意是起始点
然后就可以解题了
Bzoj3620似乎在梦中见过的样子
我们可以发现A+B+A其实就是next数组的描述QAQ
然后我们可以暴力求解答案辣
我们枚举左端点,计算出当前next数组,然后一直跳,注意不要跳过当前枚举的左端点
这样我们跳到一个位置使得串长小于我们枚举的串长的一半就记录
位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串
注意这句话,这就可以保证我们不用再算其他的串了,也就是说每个子串对答案最多贡献1
代码:
大同小异,只不过这次我们可以算多个串,所以我们记录一个cnt数组表示再跳几次就可以到达0,也就是还有几个符合要求的前缀
事实证明我已经不会辣QAQ
趁早复习一下省的考到的时候挂了……
KMP算法就是一个next数组,记录的是一系列位置,表示当前串失配后返回一个有最长公共前缀的点,注意是起始点
然后就可以解题了
Bzoj3620似乎在梦中见过的样子
我们可以发现A+B+A其实就是next数组的描述QAQ
然后我们可以暴力求解答案辣
我们枚举左端点,计算出当前next数组,然后一直跳,注意不要跳过当前枚举的左端点
这样我们跳到一个位置使得串长小于我们枚举的串长的一半就记录
位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串
注意这句话,这就可以保证我们不用再算其他的串了,也就是说每个子串对答案最多贡献1
代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=20000+10; int n,next[maxn],ans=0,k; char s[maxn]; void kmp(int p){ for (int i=1;i<=n;++i) next[i]=p-1; for (int i=p+1;i<=n;++i){ int j=next[i-1]; while (j+1!=p&&s[j+1]!=s[i]) j=next[j]; if (s[j+1]==s[i]) j++; next[i]=j; } int j=next[p]; for (int i=p+1;i<=n;++i){ while (j!=p-1&&s[j+1]!=s[i]) j=next[j]; if (s[j+1]==s[i]) j++; while ((j-p+1)*2>=(i-p+1)) j=next[j]; if (j-p+1>=k) ans++; } } int main(){ scanf("%s%d",s+1,&k); n=strlen(s+1); for (int i=1;i<=n;++i)kmp(i); printf("%d",ans); }Bzoj3670动物园
大同小异,只不过这次我们可以算多个串,所以我们记录一个cnt数组表示再跳几次就可以到达0,也就是还有几个符合要求的前缀
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define LL long long using namespace std; const int maxn=1e6+1000; const LL mod=1000000007; int cnt[maxn],next[maxn],n; char s[maxn]; void getans(){ cnt[1]=1; for (int i=2;i<=n;++i){ int j=next[i-1]; while (j&&s[j+1]!=s[i]) j=next[j]; if (s[j+1]==s[i]) j++; next[i]=j; cnt[i]=cnt[j]+1; } int j=0; LL ans=1; for (int i=2;i<=n;++i){ while (j&&s[j+1]!=s[i]) j=next[j]; if (s[j+1]==s[i]) j++; while ((j<<1)>i) j=next[j]; ans=(ans*1LL*(cnt[j]+1))%mod; } printf("%lld\n",ans); } int main(){ int T; scanf("%d",&T); for (int i=1;i<=T;++i){ scanf("%s",s+1); n=strlen(s+1); getans(); } }
相关文章推荐
- 用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用
- 经典算法与数据结构的c++实现——插入排序
- 1089: [SCOI2003]严格n元树 DP+高精度
- BZOJ1072: [SCOI2007]排列perm
- ubuntu 没有权限打开串口
- Mysql与MongoDB对比测试
- MongoDB之php操作
- “网红时代”大趋势下另类做淘宝的高效套路
- MongoDB:用户认证
- FZU 2099 魔法阵
- MongoDB2.0安装配置
- FZU 2098 刻苦的小芳
- FZU 2095 水面高度
- JDK配置环境变量的原因(windows)
- 17. Letter Combinations of a Phone Number | Java最短代码实现
- old linkedin profile
- WCF入门教程——一个简单Demo(六)
- ES5 对象的扩展(Object.preventExtensions)、密封(Object.seal)和冻结(Object.freeze)
- IE10/11克隆textarea时 bug
- struts2中的addActionError 、addFieldError、addActionMessage的方法