应同机房某大佬的要求来写这篇题解ios
给定一个字符串 \(S\) 和一个数 \(K\),要求求出 \(S\) 的全部形似 \(A+B+A\) 的子串数量,其中 \(\mid A\mid \ge K\),\(\mid B\mid \ge 1\)数组
位置不一样其余性质相同的子串算不一样子串,位置相同但拆分不一样的子串算同一子串spa
设 \(S\) 的长度为 \(n\)code
对于 \(S\) 从 \(1\) 到 \(n\) 的每个位置,以当前位置的字符做为一个子串的起点,而后寻找它的终点,来肯定当前子串是否知足条件ip
对于 \(Next\) 数组的预处理仍是相同操做,可是每换一个起点就要从新处理一次,只处理从当前位置到最后的字符字符串
对于每一个子串的终点,能够发现,只要在知足总长度的状况下不停回溯,才能统计全部的状况get
回溯到最后的位置就是与它相同的最初子串的结束位置,由于不一样位置相同子串算做同一子串,因此遇到相同的时,回溯到第一个相同子串即可统计string
同理,若第一个相同子串不知足长度限制,那么后面的一定也不知足长度限制io
具体原理请参考 KMP 的 \(Next\) 数组的原理class
最后再判断一会儿串的相同先后缀长度是否知足大于 \(K\) 就行了
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #define maxn 1000010 using namespace std; int Nxt[maxn],J,n,k; int ans; char s[maxn]; int read(){ int s=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar(); return s*w; } void Kmp(int Begin){ J=Begin-1;Nxt[Begin]=Nxt[Begin-1]=J; for(int i=Begin;i<n;i++){ while(J>Begin-1&&s[J+1]!=s[i+1]) J=Nxt[J]; if(s[J+1]==s[i+1]) J++; Nxt[i+1]=J; } for(int i=Begin;i<n;i++){ J=Nxt[i+1];// while(J>Begin-1&&Begin+2*(J-Begin+1)>i+1) J=Nxt[J];// if(J-Begin+1>=k) ans++; } } int main(){ scanf("%s",s+1);k=read(); n=strlen(s+1);Nxt[0]=Nxt[1]=1; for(int i=1;i<=n;i++) Kmp(i); printf("%d",ans); return 0; }