ZOJ3587 Marlon's String KMP技巧处理
2016-03-26 14:10
381 查看
题意:给定一个 T 串,一个 S 串,问由 S 串中的两个子串组成 T 串有多少种方式?
思路:这道题让我搞了好久,举个例子,将T串分成任意两段,那么必然是从中间断开的,即我们就需要在S中寻找和T的前半段匹配的子串数量,记录在V1数组中,和T的后半段匹配的子串的数量,记录在V2数组中,最后求出 V1[1]*V2[strlen(T)-1]+V1[2]*V2[strlen(T)-2]+……+V1[strlen(T)-1]*V2[1] 即可。
我的做法是将两个字符串连接,T在前S在后,同时在连接处加一个不相关字符‘*’,这样做是为了避免next数组在S中寻找子串的时候也计算上了T串的字符,计算前半段匹配直接遍历next数组就可以了,计算后半段则是将两字符串均翻转后连接。,之后通过next数组在其中寻找子串。但这样做还是有可能遗漏一些子串,比如next只会记录最长匹配,但是往往这些最长匹配中也包含了一些次长的匹配,我们可以通过next跳跃将这些遗漏处补充上(跳跃方式很简单 看代码注释),这样就可以得到完整的V1和V2数组了。最后千万别忘了 V1,V2和sum都是long long 才行哦。
代码如下:
思路:这道题让我搞了好久,举个例子,将T串分成任意两段,那么必然是从中间断开的,即我们就需要在S中寻找和T的前半段匹配的子串数量,记录在V1数组中,和T的后半段匹配的子串的数量,记录在V2数组中,最后求出 V1[1]*V2[strlen(T)-1]+V1[2]*V2[strlen(T)-2]+……+V1[strlen(T)-1]*V2[1] 即可。
我的做法是将两个字符串连接,T在前S在后,同时在连接处加一个不相关字符‘*’,这样做是为了避免next数组在S中寻找子串的时候也计算上了T串的字符,计算前半段匹配直接遍历next数组就可以了,计算后半段则是将两字符串均翻转后连接。,之后通过next数组在其中寻找子串。但这样做还是有可能遗漏一些子串,比如next只会记录最长匹配,但是往往这些最长匹配中也包含了一些次长的匹配,我们可以通过next跳跃将这些遗漏处补充上(跳跃方式很简单 看代码注释),这样就可以得到完整的V1和V2数组了。最后千万别忘了 V1,V2和sum都是long long 才行哦。
代码如下:
#include <iostream> #include <algorithm> #include <cstring> using namespace std; const int maxn=100005; int NEXT[maxn<<1]; char s[maxn]; char t[maxn]; char st[maxn<<1]; long long v1[maxn]; long long v2[maxn]; void get_NEXT(char *p){ int k=-1; int j=0; int n=strlen(p); NEXT[0]=-1; while(j<n){ if(k==-1||p[j]==p[k]){ k++; j++; NEXT[j]=k; } else k=NEXT[k]; } } int main() { ios::sync_with_stdio(false); int T; cin>>T; while(T--){ memset(st,0,sizeof(st)); memset(v1,0,sizeof(v1)); memset(v2,0,sizeof(v2)); cin>>s>>t; strcat(st,t); st[strlen(st)]='*'; strcat(st,s); get_NEXT(st); int ns=strlen(s); int nt=strlen(t); int n=strlen(st); for(int i=nt+2;i<=n;i++){ v1[NEXT[i]]++; } for(int i=nt;i>1;i--){ //next数组跳跃补充遗漏。即最大匹配包含了次大匹配 v1[NEXT[i]]+=v1[i]; } memset(st,0,sizeof(st)); int Count=0; for(int i=nt-1;i>=0;i--){ st[Count++]=t[i]; } st[Count++]='*'; for(int i=ns-1;i>=0;i--){ st[Count++]=s[i]; } get_NEXT(st); for(int i=nt+2;i<=n;i++){ v2[NEXT[i]]++; } for(int i=nt;i>1;i--){ //next数组跳跃补充遗漏。即最大匹配包含了次大匹配 v2[NEXT[i]]+=v2[i]; } long long sum=0; for(int i=1;i<nt;i++){ sum += v1[i]*v2[nt-i]; } cout<<sum<<endl; } return 0; }
相关文章推荐
- sublime text 3注释快捷键ctrl+/失效解决方案
- asp.net core 笔记
- Delphi_03_Delphi_Object_Pascal_基本语法_01
- 数据结构之线性表ArrayList小结(一)
- 中国剩余定理(韩信点兵)
- machine learning实验7 矩阵求逆
- 程序DEBUG和运行结果不一致??不要在DEBUG中监视ResultSet了!!
- VS2012 的插件安装后,出现的ActivityLog.xml 日记错误的解决方案
- 2440test 裸机測试 调试不进main 设置改动方法
- 76. Minimum Window Substring My Submissions Question
- 3-5 RPM包校验
- Unity3D学习1——鼠标点击效果显示
- Machine Learning实验6 理解核函数
- ECHI和OCHI
- 60. Permutation Sequence
- [LeetCode]Missing Number
- 如何让ARM板启动的时候就运行自己的QT程序
- 来CSDN写博客的一些原因
- 底层const
- 双击文件夹新建一个窗口问题