HDU 4333:Revolving Digits KMP+扩展KMP
2016-02-25 15:44
399 查看
扩展KMP的姿势
扩展KMP可以在O(n)的复杂度内求这样一个问题:
给定两个串S,T,设n=|S|,m=|T|求S中的每个后缀与T的最长公共前缀,用extend[i]表示。即extend[i]=LCP(S[i..n],T)
算法过程:
类似的,我们令next[i]表示T中的每个后缀与T的最长公共前缀,即next[i]=LCP(T[i..m],T)
令k表示当前k+next[k]−1最大的k,并令p=k+next[k]−1。
假设当前要计算extend[i],易知S[k..p]=T[1..p−k+1],
则有S[i..p]=T[i−k+1,p−k+1]。
令L=next[i−k+1],
若L<p−i+1,则extend[i]=L。
否则,先令extend[i]=p−i+1(注意p−i+1不能<0,如果<0就赋为0),然后从S[i+next[i]]与T[next[i]+1]向后匹配,直到失配为止。
算法结束后,如果当前i+next[i]>k+next[k],则更新k。
求解next数组的过程与本过程类似,其实就是T自身的扩展KMP过程。
扩展KMP算法是十分优秀的,常见的应用有:
1.求最长公共前缀。
2.求解重复子串的长度:
如串abababc,next[3]=4,next[5]=2,重复子串ababab的长度即i+next[i]−1=6,再如串ababa,next[3]=3,next[5]=1,重复子串ababa的长度即i+next[i]−1=5。所以重复子串的长度=端点处的i+next[i]−1,若最后一个循环节不完整也将其算在内。
然后这道题,我们可以把原串补在后面一遍,然后求出next数组,若next[i]>=len,证明两个串相等,否则我们只需要比较s[next[i]+1]与s[i+next[i]]的大小,就能得出两个串的大小关系。
然后至于重复的串,我们可以用kmp来求一下最小循环节,将三个答案都除以最小循环节出现的个数就好了。
扩展KMP可以在O(n)的复杂度内求这样一个问题:
给定两个串S,T,设n=|S|,m=|T|求S中的每个后缀与T的最长公共前缀,用extend[i]表示。即extend[i]=LCP(S[i..n],T)
算法过程:
类似的,我们令next[i]表示T中的每个后缀与T的最长公共前缀,即next[i]=LCP(T[i..m],T)
令k表示当前k+next[k]−1最大的k,并令p=k+next[k]−1。
假设当前要计算extend[i],易知S[k..p]=T[1..p−k+1],
则有S[i..p]=T[i−k+1,p−k+1]。
令L=next[i−k+1],
若L<p−i+1,则extend[i]=L。
否则,先令extend[i]=p−i+1(注意p−i+1不能<0,如果<0就赋为0),然后从S[i+next[i]]与T[next[i]+1]向后匹配,直到失配为止。
算法结束后,如果当前i+next[i]>k+next[k],则更新k。
求解next数组的过程与本过程类似,其实就是T自身的扩展KMP过程。
扩展KMP算法是十分优秀的,常见的应用有:
1.求最长公共前缀。
2.求解重复子串的长度:
如串abababc,next[3]=4,next[5]=2,重复子串ababab的长度即i+next[i]−1=6,再如串ababa,next[3]=3,next[5]=1,重复子串ababa的长度即i+next[i]−1=5。所以重复子串的长度=端点处的i+next[i]−1,若最后一个循环节不完整也将其算在内。
然后这道题,我们可以把原串补在后面一遍,然后求出next数组,若next[i]>=len,证明两个串相等,否则我们只需要比较s[next[i]+1]与s[i+next[i]]的大小,就能得出两个串的大小关系。
然后至于重复的串,我们可以用kmp来求一下最小循环节,将三个答案都除以最小循环节出现的个数就好了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int a,b,c,len; int p[100005],q[100005]; char s[200005]; int main() { int testcase; scanf("%d",&testcase); for (int T=1;T<=testcase;T++) { scanf("%s",s+1); int j=0; p[1]=0; len=strlen(s+1); for (int i=2;i<=len;i++) { while (j&&s[j+1]!=s[i]) j=p[j]; if (s[j+1]==s[i]) j++; p[i]=j; } int tmp=len%(len-p[len])==0?len/(len-p[len]):1; for (int i=1;i<=len;i++) s[i+len]=s[i]; len<<=1; int p=1; q[1]=len; while (p<=len&&s[p]==s[p+1]) p++; q[2]=p-1; int k=2; for (int i=3;i<=len>>1;i++) { int p=k+q[k]-1; q[i]=min(q[i-k+1],max(p-i+1,0)); while (i+q[i]<=len&&s[q[i]+1]==s[i+q[i]]) q[i]++; if (i+q[i]>k+q[k]) k=i; } len>>=1; a=b=c=0; for (int i=1;i<=len;i++) if (q[i]>=len) b++; else if (s[q[i]+1]>s[i+q[i]]) a++; else c++; printf("Case %d: %d %d %d\n",T,a/tmp,b/tmp,c/tmp); } return 0; }
相关文章推荐
- linux正则表达式入门及文件操作命令进阶
- VS2008中OGRE1.7.4下配置Hydrax-v0.5.1插件
- SQL2005 性能监视器计数器错误解决方法
- baseModel
- Linux下svn密码问题
- 在Windows下搭建Android开发环境
- 电信主机计费系统_数据采集子模块
- MFC中单文档程序框架
- [.Net码农]C# WebService异步处理/异步调用详解
- 关于Linux下进程间使用共享内存和信号量通信的时的编译问题
- Timestamp,Date和String的互相转换
- java web程序中web.xml文件中servlet-name、url-pattern的值不能与映射的类名一致,否则tomcat启动不了,报错误: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/Servlet_day02]]
- PHP运算符
- 关于16年2月14日以后上传AppStore出现:Missing iOS Distribution signing identity for...的问题
- ZOJ 3582 概率DP
- Android:友盟分享 AS开发配置
- dblp 介绍 使用,计算机领域内对研究的成果以作者为核心的一个计算机类英文文献的集成数据库系统
- 面试题四 C/C++面试秘笈 之判断链表是否存在环形链表问题-程序员面试题
- linux中java调用shell脚本
- centos下网络配置方法(网关、dns、ip地址配置)