HDU 1358 Period【KMP】
题意: 一个字符串,从头到某个位置,字符串的前缀最多重复了多少次。
转一相关讲解:
kmp next函数 kmp的周期问题,深入了解kmp中next的原理
-----------------------
-----------------------
k m x j i
由上,next【i】=j,两段红色的字符串相等(两个字符串完全相等),s[k....j]==s[m....i]
设s[x...j]=s[j....i](xj=ji)
则可得,以下简写字符串表达方式
kj=kx+xj;
mi=mj+ji;
因为xj=ji,所以kx=mj,如下图所示
-------------
-------------
k m x j
看到了没,此时又重复上面的模型了,kx=mj,所以可以一直这样递推下去
所以可以推出一个重要的性质len-next[i]为此字符串的最小循环节(i为字符串的结尾),另外如果len%(len-next[i])==0,此字符串的最小周期就为len/(len-next[i]);
求给定字符串含前缀的数量
abab
前缀为
a
ab
aba
abab
abab中共有六个子串是前缀a a ab ab aba abab
所以答案为6
利用kmp中的匹配原理可以完美的解决此题
a---------d-----
-----a---------d
i j
如上所示,假设两串字符完全相等,next[j]=i,代表s[1...i]==sum[j-i+1....j],这一段其实就是前缀
i~j之间已经不可能有以j结尾的子串是前缀了,不然next【j】就不是 i 了
设dp【i】:以string[i]结尾的子串总共含前缀的数量
所以dp[j]=dp[i]+1,即以i结尾的子串中含前缀的数量加上前j个字符这一前缀
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> char m[1000002]; int next[1000002]; int n; void get() { int i=0,j=-1; next[0]=-1; while(i<n) { if(j==-1||m[i]==m[j]) { i++; j++; next[i]=j; } else j=next[j]; } } int main() { int k,i,ca=1; while(scanf("%d",&n),n) { scanf("%s",m); get(); printf("Test case #%d\n",ca++); for(i=2;i<=n;i++) { k=i-next[i]; if(i%k==0&&i/k>1) printf("%d %d\n",i,i/k); } printf("\n"); } }