KMP模板

kmp算法的主要作用在于对next数组的运用,所以这里只给出next数组的模板

性质1:对于每一个长度len的子串,该子串的最小循环节为len-next[len]

性质2:kmp的next不断向前递归的过程可以保证对于每一个当前前缀,都有一段后缀与之对应

#include<iostream>
#include<cstring>
#define maxn 100010
using namespace std;
int next[maxn];
char s[maxn];
char p[maxn];void prekmp(char x[],int m,int Next [])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(j!=-1&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}
}
//计数 可重复
int kmpcount(char pp[],int m,char ss[],int n)
{int ans = 0;int i,j;i = j = 0;prekmp(pp,m,next);while(i<n){while(j!=-1&&ss[i]!=pp[j]) j = next[j];i++;j++;if(j>=m){ans++;j = next[j];}}return ans;
}
//计数 不可重复
int kmpcount(char pp[],int m,char ss[],int n)
{int ans = 0;int i,j;i = j = 0;prekmp(pp,m,next);while(i<n){while(j!=-1&&ss[i]!=pp[j]) j = next[j];i++;j++;if(j>=m){ans++;j = 0;}}return ans;
}
//返回位置
int kmp(char pp[],int m,char ss[],int n)
{int ans = 0;int i,j;i = j = 0;prekmp(pp,m,next);while(i<n){while(j!=-1&&ss[i]!=pp[j]) j = next[j];i++;j++;if(j>=m){ans = i-j;return ans;}}return -1;}

基础题

HDU1711

题意就是给你两个序列,让你求B序列在A序列第一次出现(完全相同)的下标

这道题是一道板子题,直接用返回位置的那个板子贴上就过了,不过还是要注意细节问题,输入输出尽量用printf、scanf,不然会tle,开数组卡着边界开,不然会mle,另外注意输入输出格式 ,不然会pe。代码在下面?

#include<iostream>
#include<cstring>
#include<stdio.h>
const int maxn = 1e6+5;using namespace std;
int NEXT[maxn];
int pat[maxn];
int str[maxn];
void prekmp(int x[],int m,int Next[])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(j!=-1&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}
}int kmp (int p[],int m,int s[],int n)
{int i,j;int ans = 0;i = j = 0;prekmp(p,m,NEXT);while(i<n){while(j!=-1&&p[j]!=s[i]) j = NEXT[j];i++;j++;if(j>=m){ans = i-m+1;return ans;}}return -1;
}int main()
{int t = 0;cin>>t;for(int i=0;i<t;i++){int n,m;scanf("%d%d",&n,&m);for(int j=0;j<n;j++){scanf("%d",&str[j]);}for(int j=0;j<m;j++){scanf("%d",&pat[j]);}int ans = kmp(pat,m,str,n);printf("%d\n",ans);}return 0;
}

HDU1686

题意就是求B串在A串中的出现次数(可重叠 )

这道题同样是板子题,用计数可重复那个板子,主要是可以做做这道题熟悉一下板子。

还有就是板子题,大家背板子的时候一定要背对了啊,尤其是条件。

#include<iostream>
#include<cstring>using namespace std;const int maxn = 1e4+5;
int NEXT[maxn];
char pat[maxn];
char str[1000005];
void prekmp(char x[],int m,int Next [])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(j!=-1&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}
}
int kmpcount(char p[],int m,char s[],int n)
{int ans = 0;int i,j;i = j = 0;prekmp(p,m,NEXT);while(i<n){while(j!=-1&&s[i]!=p[j]) j = NEXT[j];i++;j++;if(j>=m){ans++;j = NEXT[j];//j = 0;}}return ans;
}
int main()
{int t;cin>>t;for(int i=0;i<t;i++){cin>>pat;cin>>str;int m = strlen(pat);int n = strlen(str);int ans = kmpcount(pat,m,str,n);cout<<ans<<endl;}return 0;
}

HDU2087

题意是主串能切出几个子串,言下之意是不能重复

这道题还是一个板子题,直接贴那个计数不重复那个就过了。

需要注意的是输入方法。

#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
const int maxn = 1e5+5;
int NEXT[maxn];
char pat[maxn];
char str[1000005];void prekmp(char x[],int m, int Next[])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(j!=-1&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}
}
int kmp(char p[],int m,char s[],int n)
{int i,j;int ans = 0;i = j = 0;prekmp(p,m,NEXT);while(i<n){while(j!=-1&&p[j]!=s[i]) j = NEXT[j];i++;j++;if(j>=m){ans++;j = 0;}}return ans;
}int main()
{while(scanf("%s",str)!=EOF){int n = strlen(str);if(n==1&&str[0]=='#') break;scanf("%s",pat);int m = strlen(pat);printf("%d\n",kmp(pat,m,str,n));}return 0;
}

到现在应该板子很熟了,下面练一下next数组的性质。

HDU3746

题意为添加最少的字符使原字符串变成周期至少为2的循环字符串

这道题利用了next数组的特性,结论是长度为m的pattern串的循环结长度为m-next[m]

代码如下:

#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;const int maxn = 100005;
int NEXT[maxn];
char pat[maxn];void prekmp(char x[],int m,int Next[])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(j!=-1&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}
}
int kmp(char p[], int m)
{int ans = 0;prekmp(p,m,NEXT);ans = m - NEXT[m];///最小循环结return ans;
}
int main()
{int t;cin>>t;for(int i=0;i<t;i++){char pat[maxn];scanf("%s",&pat);int m = strlen(pat);int ans = kmp(pat,m);if(m%ans==0&&m!=ans){printf("0\n");}else{int x = m%ans;printf("%d\n",ans-x);}}return 0;
}

HDU1358

这道题和上题类似同样用到next数组与最小循环结的应用,m-next[m]

代码如下:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std ;
const int maxn = 1e6+5;
int NEXT[maxn];
char str[maxn];
char mo[maxn];
int n1,n2;
void prekmp(char x[],int m,int Next[])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(j!=-1&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}
}
int main()
{int cnt=1;while(scanf("%d",&n2)!=EOF){if(n2==0) break;scanf("%s",mo);NEXT[0]=-1;prekmp(mo,n2,NEXT);printf("Test case #%d\n",cnt++);for(int i=1;i<=n2;i++){int tmp=i-NEXT[i];if(i/tmp==1) continue;if(i%tmp==0){printf("%d %d\n",i,i/tmp);}}printf("\n");}return 0;
}

POJ2406

题意是给定字符串,输出循环周期。

这道题还是用到了next数组循环结那个性质。

代码如下:

#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
const int maxn  = 1000005;
int NEXT[maxn];
char pat[maxn];
void kmp(char x[],int m,int Next[])
{int i,j;j = Next[0] = -1;i = 0;while(i<m){while(-1!=j&&x[i]!=x[j]) j = Next[j];Next[++i] = ++j;}return;
}int main()
{while(scanf("%s",pat)){if(strcmp(pat,".")==0)break;int m = strlen(pat);kmp(pat,m,NEXT);int l = m-NEXT[m];if(m%l==0)printf("%d\n",m/l);elseprintf("1\n");}return 0;
}

POJ2752

本题题意为求出所有在后缀中出现过的前缀的最后一个元素的下标 
本题要考虑一下next数组的本质,其实就是最长的出现在后缀中的前缀,但是由于本题要求所有的而不是最长的,考虑到next数组的递归过程,其实就是对每一个当前长度的前缀,都有完全相同的后缀与之对应,所以就不断递归next数组即可求解。 
POJ2752代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std ;
const int maxn = 1e6+5;
int ans[maxn];
int Next[maxn];
char str[maxn];
char mo[maxn];
int n1,n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int main()
{int cnt;while(scanf("%s",mo)!=EOF){cnt=0;n2=strlen(mo);Next[0]=-1;GetNext();int j=n2;while(j!=0){ans[cnt++]=j;j=Next[j];}for(int i=cnt-1;i>=0;i--){printf("%d%c",ans[i],i==0?'\n':' ');}}return 0;
}

POJ3080

本题题意为求m个字符串长度至少为3的最长公共子串 
由于m只有10而且len小于60,我们可以选择枚举某一个串的子串并用str.find()或者kmp验证是否所有该子串在所有字符串中出现过,也可以用经典的二分长度将height数组分块的后缀数组做法 
POJ3080(find解法

//由于只查找是否出现过,算法复杂度差距不大,所以这里给出简单一些的写法
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn = 65;
char str[maxn];
string ansstr;
string str2[maxn];
int main()
{int n,t;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n;i++){scanf("%s",str);str2[i]=str;}int ans=0;string tmp=str2[0];int tmplen=tmp.size();for(int i=0;i<tmplen;i++){for(int j=1;i+j<=tmplen;j++){int cnt=1;string ss=tmp.substr(i,j);for(int k=1;k<n;k++){if(str2[k].find(ss)!=-1)cnt++;}if(cnt==n){if(ans<j){ans=j;ansstr=ss;}else if(ans==j){ansstr=min(ansstr,ss);}}}}if(ans<3) printf("no significant commonalities\n");else printf("%s\n",ansstr.c_str());}
}

POJ3080(后缀数组写法

//具体实现原理可以参考我的后缀数组博客
#include <iostream>
#include<algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;
#define maxn 4005
const int INF = 0x3f3f3f3f;
int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
int rank[maxn],height[maxn],s[maxn];
char str[15][65];
int t,lenn[maxn];
int belong[maxn];
int anspos;
int vis[65];
int cmp(int *r,int a,int b,int k)
{return r[a]==r[b]&&r[a+k]==r[b+k];
}
void getsa(int *r,int *sa,int n,int m)
{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++)  wsf[i]=0;for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;p=1;j=1;for(; p<=n; j*=2,m=p){for(p=0,i=n+1-j; i<=n; i++)  y[p++]=i;for(i=0; i<=n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;for(i=0; i<=n; i++)  wv[i]=x[y[i]];for(i=0; i<m; i++)  wsf[i]=0;for(i=0; i<=n; i++)  wsf[wv[i]]++;for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];t=x;x=y;y=t;x[sa[0]]=0;for(p=1,i=1; i<=n; i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;}
}
void getheight(int *r,int n)
{int i,j,k=0;for(i=1; i<=n; i++)  rank[sa[i]]=i;for(i=0; i<n; i++){if(k)k--;elsek=0;j=sa[rank[i]-1];while(r[i+k]==r[j+k])k++;height[rank[i]]=k;}
}
int check(int x,int n)
{for(int i=1;i<=n-1;i++){if(height[i]<x) continue;int cnt=0;for(int j=0;j<=t;j++) vis[j]=0;while(height[i]>=x&&i<=n-1){if(!vis[belong[sa[i-1]]]){vis[belong[sa[i-1]]]=1;cnt++;}i++;}if(!vis[belong[sa[i-1]]]){vis[belong[sa[i-1]]]=1;cnt++;}if(cnt>=t){anspos=sa[i-1];return true;}}return false;
}
int main()
{int len,n;int casee;scanf("%d",&casee);while(casee--){scanf("%d",&t);if(t==0) break;n=0;int pos=30;for(int i=0;i<t;i++){scanf("%s",str[i]);lenn[i]=strlen(str[i]);for(int j=0;j<lenn[i];j++){s[n++]=str[i][j]-'A'+1;belong[n-1]=i;}s[n++]=pos++;}s[n]=0;getsa(s,sa,n,pos);getheight(s,n);int l=1,r=60,mid;while(l<=r){mid=(l+r)>>1;if(check(mid,n)) l=mid+1;else r=mid-1;}if(r<3) printf("no significant commonalities  \n");else{for(int i=anspos;i<anspos+r;i++)printf("%c",s[i]-1+'A');printf("\n");}}return 0;
}

HDU2594

本题题意是求既是A串中的前缀又是B串中的后缀的最长长度。 
如果我们将AB进行拼接,我们可以发现next[len1+len2]next[len1+len2]即为最长的即使前缀又是后缀的子串,但是这里有一个细节,就是如果这个长度大于min(len1,len2)min(len1,len2),代表这个是拼接之后产生的,是不可取的,所以我们可以运用性质2来不断减少这个长度,直到他满足len<min(len1,len2)len<min(len1,len2)即可。 
HDU2594代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std ;
const int maxn = 1e6+5;
int Next[maxn];
char str[maxn];
char mo[maxn];
int n1,n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int main()
{int cnt;while(scanf("%s%s",mo,str)!=EOF){n1=strlen(str);n2=strlen(mo);int tmp=n2;for(int i=n2;i<n2+n1;i++){mo[i]=str[i-n2];}n2=n1+n2;mo[n2]='\0';Next[0]=-1;GetNext();int ans=Next[n2];while(ans>min(tmp,n2-tmp)){ans=Next[ans];}if(ans==0){printf("0\n");continue;}for(int i=0;i<ans;i++)printf("%c",mo[i]);printf(" ");printf("%d\n",ans);}return 0;
}

HDU3336

本题题意为求字符串的每个前缀在整个字符串中的出现次数。 
我们想象性质二,如果next[j]对答案有一个贡献,那么这个贡献在j中一定会再贡献一次,而且j为结尾的字符串对于总串产生的贡献只有长度为j的子串,于是我们可以得到转移方程ans[j]=ans[next[j]]+1ans[j]=ans[next[j]]+1,最后对所有前缀的贡献取和即为答案。 
HDU3336代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std ;
const int maxn = 1e6+5;
int Next[maxn];
char str[maxn];
char mo[maxn];
int dp[maxn];
int n1,n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int kmp()
{int cnt=0;int i=0,j=0;while(i<n1){if(j==-1||str[i]==mo[j]) i++,j++;else j=Next[j];if(j==n2){cnt++;j=0;}}return cnt;
}
int ans[maxn];
int main()
{int cnt;int t;scanf("%d",&t);while(t--){scanf("%d%s",&n2,mo);Next[0]=-1;GetNext();int ans=0;dp[0]=0;for(int i=1;i<=n2;i++){dp[i]=dp[Next[i]]+1;ans=(ans+dp[i])%10007;}printf("%d\n",ans);}return 0;
}

HDU4300

本题题意比较难读懂,题意为给你一段密文的映射方式和一段密文+明文的字符串,密文是完整的,而明文不一定是完整的,让你添加最少的字符使他变为完整的密文+明文 
如果读懂题意,可以考虑给定字符串中密文长度一定是>=len/2>=len/2的,所以我们可以将后半段的字符均按照映射换为密文,然后找到最长的既在前缀中出现又在后缀中出现的子串,根据性质二和第九题的做法,不断递归next直到找到符合条件的lenlen然后跳出即可,输出时要注意明文密文的转换 
HDU4300代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std ;
const int maxn = 1e5+5;
int Next[maxn];
char str[maxn];
char str2[maxn];
char mo[maxn];
int dp[maxn];
int mm[30];
int nn[maxn];
int n1,n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int ans[maxn];
int main()
{int cnt;int t;scanf("%d",&t);while(t--){scanf("%s%s",str,mo);strcpy(str2,mo);n2=strlen(mo);n1=strlen(str);for(int i=0;i<n1;i++){mm[i]=str[i]-'a';nn[str[i]-'a']=i;}for(int i=0;i<(n2+1)/2;i++){mo[i]=nn[mo[i]-'a']+'a';}Next[0]=-1;GetNext();int ans=Next[n2];while(ans>min((n2+1)/2,n2-(n2+1)/2)){ans=Next[ans];}for(int i=0;i<n2-ans;i++)printf("%c",str2[i]);for(int i=0;i<n2-ans;i++)printf("%c",nn[str2[i]-'a']+'a');printf("\n");}return 0;
}

HDU1238

多个字符串的最长公共子串,只不过子串可以逆置出现,只要把第八题的做法反过来再找一次就好,直接上代码

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn = 105;
char str[maxn];
string ansstr;
string str2[maxn];
int main()
{int n,t;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=0;i<n;i++){scanf("%s",str);str2[i]=str;}int ans=0;string tmp=str2[0];int tmplen=tmp.size();for(int i=0;i<tmplen;i++){for(int j=1;i+j<=tmplen;j++){int cnt=1;string ss=tmp.substr(i,j);for(int k=1;k<n;k++){if(str2[k].find(ss)!=-1)cnt++;}if(cnt==n){if(ans<j){ans=j;ansstr=ss;}else if(ans==j){ansstr=min(ansstr,ss);}}}}reverse(tmp.begin(),tmp.end());for(int i=0;i<tmplen;i++){for(int j=1;i+j<=tmplen;j++){int cnt=1;string ss=tmp.substr(i,j);for(int k=1;k<n;k++){if(str2[k].find(ss)!=-1)cnt++;}if(cnt==n){//  cout<<ss<<" "<<cnt<<endl;if(ans<j){ans=j;ansstr=ss;}else if(ans==j){ansstr=min(ansstr,ss);}}}}printf("%d\n",ans);}
}

HDU3374

本题题意为求一个字符串旋转后的所有串中字典序最大和字典序最小分别出现的次数。 
搜先我们要了解字符串的最小表示法o(n)o(n)的时间复杂度求出旋转后字典序最小的起始下标。 
最小表示法戳这里字符串最小表示法 
了解了最小表示法之后,我们考虑一下,会发现,只有字符串有循环节的时候才会出现旋转后有相同的串出现的情况,所以我们利用性质1判断是否字符串存在循环节,然后利用最小/最大表示法分别求出下标即可 
HDU3374代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std ;
const int maxn = 1e6+5;
int Next[maxn];
char mo[maxn];
int n1,n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int getmin(char *s)
{int n=strlen(s);int i=0,j=1,k=0,t;while(i<n && j<n && k<n){t=s[(i+k)%n]-s[(j+k)%n];if (!t) k++;else{if (t>0) i+=k+1;else j+=k+1;if (i==j) j++;k=0;}}return i<j?i:j;}
int getmax(char *s){int len = strlen(s);int i = 0, j = 1, k = 0;while(i < len && j < len && k < len){int t = s[(i+k)%len]-s[(j+k)%len];if(!t) k++;else{if(t > 0){if(j+k+1 > i) j = j+k+1;else j = i+1;}else if(i+k+1 > j) i = i+k+1;else i = j+1;k = 0;}}return i < j ? i : j;}
int ans[maxn];
int main()
{int cnt;while(scanf("%s",mo)!=EOF){n2=strlen(mo);Next[0]=-1;GetNext();int pos=getmin(mo);int pos2=getmax(mo);int tmp=n2-Next[n2];if(n2%tmp==0){printf("%d %d %d %d\n",pos+1,n2/tmp,pos2+1,n2/tmp);}else{printf("%d %d %d %d\n",pos+1,1,pos2+1,1);}}return 0;
}

​​​​​​​HDU2609

本题为给你n个01串,可以对每个串旋转任意次,求最少出现多少个不同的字符串,我们可以知道,如果两个字符串是可以旋转之后相同的,那么他们的最小表示法一定是相同的,所以我们可以求出所有字符串的最小表示法,然后用一个set去重就好了。 
HDU2609代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<set>
using namespace std;
int getmin(char *s)
{int n=strlen(s);int i=0,j=1,k=0,t;while(i<n && j<n && k<n){t=s[(i+k)%n]-s[(j+k)%n];if (!t) k++;else{if (t>0) i+=k+1;else j+=k+1;if (i==j) j++;k=0;}}return i<j?i:j;}
char str[105];
string tmp;
set<string> s;
int main()
{int n;while(scanf("%d",&n)!=EOF){s.clear();for(int i=0;i<n;i++){scanf("%s",str);tmp=str;int pos=getmin(str);string pp=tmp.substr(pos)+tmp.substr(0,pos);s.insert(pp);}printf("%d\n",(int)s.size());}return 0;
}

​​​​​​​​​​​​​​FZU1901

本题题意为求一个长度PP,使所有的

iϵ[0,size(s)−p−1]iϵ[0,size(s)−p−1]

满足

S[i]=S[i+P]S[i]=S[i+P]

本题即为性质2的终极运用,在次重复一遍,kmp的next不断向前递归的过程可以保证对于每一个当前前缀,都有一段后缀与之对应,所以对于每一个next,我们都可以将他与最后的后缀对应作为一组答案。 
FZU1901代码

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stack>
using namespace std ;
const int maxn = 1e6+5;
int Next[maxn];
char mo[maxn];
int n1,n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int ans[maxn];
int main()
{int cnt=1;int t;scanf("%d",&t);while(t--){scanf("%s",mo);n2=strlen(mo);Next[0]=-1;int pp=0;GetNext();int tmp=Next[n2];while(tmp!=0){ans[pp++]=tmp;tmp=Next[tmp];}printf("Case #%d: %d\n",cnt++,pp+1);for(int i=0;i<pp;i++)printf("%d ",n2-ans[i]);printf("%d\n",n2);}return 0;
}

​​​​​​​

UVA11475

本题题意是给你一个字符串,求出最少拼接字符数使其变为回文串 
通过思考我们可以发现,只有作为后缀的回文串对结果产生贡献,那么这个题就转变为了找最长的后缀回文子串,我们将字符串倒置再拼接上原串,求得的next[len]也就是倒置字符串的前缀与原字符串的后缀的最大匹配长度,也就是本题答案。 
UVA11475代码

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std ;
const int maxn = 1e6+5;
int Next[maxn];
char mo[maxn];
char str[maxn];
int n2;
void GetNext()
{int i=0,j=-1;while(i<n2){if(j==-1||mo[i]==mo[j]) {++i,++j,Next[i]=j;}else j=Next[j];}return ;
}
int main()
{while(scanf("%s",str)!=EOF){n2=0;int len=strlen(str);for(int i=len-1;i>=0;i--)//字符串倒置mo[n2++]=str[i];mo[n2++]='#';//拼接符for(int i=0;i<len;i++)mo[n2++]=str[i];//拼接mo[n2]='\0';Next[0]=-1;GetNext();int tmp=Next[n2];printf("%s",str);for(int i=len-1-tmp;i>=0;i--) printf("%c",str[i]);printf("\n");}return 0;
}

以上是kmp的板子题可以用来熟悉板子。

未完待续。。。

KMP模板以及入门题型总结相关推荐

  1. Smarty中文手册,Smarty教程,Smarty模板的入门教材

    Smarty中文手册,Smarty教程,Smarty模板的入门教材 首先,这份Smarty中文手册的翻译工作是由喜悦国际村村民自发组织的,不代表任何人的意见和观点.对他们的无私奉献精神,我们表示感谢, ...

  2. kuangbin专题16B(kmp模板)

    题目链接: https://vjudge.net/contest/70325#problem/B 题意: 输出模式串在主串中出现的次数 思路: kmp模板 在 kmp 函数中匹配成功计数加一, 再令 ...

  3. 玩转springboot:thymeleaf模板引擎入门程序

    一.前言 常用的模板引擎有:JSP.Velocity.Freemarker.Thymeleaf 但是,Springboot默认是不支持JSP的,默认使用thymeleaf模板引擎.而且,语法更简单,功 ...

  4. 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

    我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...

  5. HDU 1711 Number Sequence(KMP模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=1711 这道题就是一个KMP模板. 1 #include<iostream> 2 #include&l ...

  6. ECMall2.x模板制作入门系列之2(模板标签/语法)

    ECMall2.x模板制作入门系列之2(模板标签/语法)今天给大家带来一个模板语法的教程.希望能为ECMall模板制作者提供一份参考资料.如有问题.建议和意见,欢迎提出.在ECMall模板中,用&qu ...

  7. POJ:3461-Oulipo(KMP模板题)

    原题传送:http://poj.org/problem?id=3461 Oulipo Time Limit: 1000MS Memory Limit: 65536K Description The F ...

  8. 扩展KMP模板(学习)

    学习链接:https://www.luogu.org/problemnew/solution/P5410 一.引言 一个算是冷门的算法(在竞赛上),不过其算法思想值得深究. 二.前置知识 kmp的算法 ...

  9. Oulipo(欧力波)(经典kmp模板题) HDU-1686

    题目:Oulipo(欧力波) 中文大意 The French author Georges Perec (1936�C1982) once wrote a book, La disparition, ...

  10. POJ Oulipo(KMP模板题)

    题意:找出模板在文本串中出现的次数 思路:KMP模板题 #include<cstdio> #include<cstring> #include<cmath> #in ...

最新文章

  1. java继承和多态的实验报告_JAVA,继承和多态实验报告
  2. 【opencv】6.视频编码格式与封装格式
  3. In-Loop Filters in HEVC
  4. 浅谈:ArrayList,ListT,ListObject
  5. 第十一届 蓝桥杯 单片机设计与开发项目 省赛 程序设计试题及源码
  6. windows组件向导里没有internet 信息服务(iis) 的解决办法
  7. QC与WIN7、IE8 兼容问题解决方案
  8. python源码脚本实例_python编写一个会算账的脚本的示例代码
  9. 寻找创业方向的3个方法
  10. 两台服务器安装redis集群_高性能分布式存储服务Minio安装配置入门
  11. Python训练文本情感分析模型
  12. ssm-学子商城-项目第五天
  13. 【破解软件】知音漫客免费看更多漫画
  14. windows2019关闭Windows server的IE浏览器的增强安全配置
  15. 2018年系统架构设计师案例分析真题及详细答案解析
  16. eleme后台的el-form表单分为左右两边放数据 :inline=true
  17. 搭建自己的私有云盘系统(owncloud)
  18. python3电商平台论坛_2.电商平台零售数据分析
  19. MapServer 之 发布网络地图服务(WMS-Web Map Service)
  20. Jeecg 任意文件下载漏洞

热门文章

  1. 【安全牛学习笔记】初识sql注入漏洞原理
  2. docker深入2-API示例
  3. 搭建nfs共享存储服务之三客户端配置
  4. Xshell中文乱码怎么处理?
  5. Ubuntu14.04桌面版 apt-get 方式安装LNMP
  6. Maven与Ant使用reportNG代替testng
  7. DS4300电池即将过期,磁阵目前读写缓慢解决过程.txt
  8. centos出现“FirewallD is not running”
  9. AI2(App Inventor 2)离线版服务器单机版
  10. Ajax异步请求阻塞情况的解决办法(asp.net MVC Session锁的问题)