昨天把KMP复习了一下,顺便做了一些以前做过的题,貌似有那么点感觉O(∩_∩)O~
贴出来,方便以后复习,O(∩_∩)O~
http://poj.org/problem?id=1961
POJ 1961 Period
大意:
定义字符串A,若A最多由n个相同字串s连接而成,则A=s^n,如"aaa" = "a"^3,"abab" = "ab"^2
"ababa" = "ababa"^1
给出一个字符串A,求该字符串的所有前缀中有多少个前缀SA= s^n(n>1)
输出符合条件的前缀长度及其对应的n
如aaa
前缀aa的长度为2,由2个'a'组成
前缀aaa的长度为3,由3个"a"组成
分析:KMP
若某一长度L的前缀符合上诉条件,则
1.next[L]!=0(next[L]=0时字串为原串,不符合条件)
2.L%(L-next[L])==0(此时字串的长度为L/next[L])
对于2:有str[0]....str[next[L]-1]=str[L-next[L]-1]...str[L-1]
=》str[L-next[L]-1] = str[L-next[L]-1+L-next[L]-1] = str[2*(L-next[L]-1)];
假设S = L-next[L]-1;则有str[0]=str[s]=str[2*s]=str[3*s]...str[k*s],对于所有i%s==0,均有s[i]=s[0]
同理,str[1]=str[s+1]=str[2*s+1]....
str[j]=str[s+j]=str[2*s+j]....
综上,若L%S==0,则可得L为str[0]...str[s-1]的相同字串组成,
总长度为L,其中字串长度SL = s-0+1=L-next[L],循环次数为L/SL
故对于所有大于1的前缀,只要其符合上述条件,即为答案之一
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
stdio.h
>
#include < string .h >
const int N = 1000000 + 10 ;
char str[N];
int next[N];
int len;
void GetNext1( char str[N], int next[N]) // 寻找模式串的粗略next
{
int l = strlen(str);
next[ 0 ] =- 1 ;
int i = 0 ,j =- 1 ;
while (i < l)
{
if (j ==- 1 || str[i] == str[j])
{
i ++ ;j ++ ;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
int T = 0 ;
while (scanf( " %d " , & len) != EOF)
{
T ++ ;
if (len == 0 ) break ;
scanf( " %s " ,str);
GetNext1(str,next);
int i;
printf( " Test case #%d\n " ,T);
for (i = 2 ;i <= len;i ++ )
{
if (next[i] != 0 && i % (i - next[i]) == 0 ) // 保证不是原串且循环
{
printf( " %d %d\n " ,i,i / (i - next[i]));
}
}
printf( " \n " );
}
return 0 ;
}
#include < string .h >
const int N = 1000000 + 10 ;
char str[N];
int next[N];
int len;
void GetNext1( char str[N], int next[N]) // 寻找模式串的粗略next
{
int l = strlen(str);
next[ 0 ] =- 1 ;
int i = 0 ,j =- 1 ;
while (i < l)
{
if (j ==- 1 || str[i] == str[j])
{
i ++ ;j ++ ;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
int T = 0 ;
while (scanf( " %d " , & len) != EOF)
{
T ++ ;
if (len == 0 ) break ;
scanf( " %s " ,str);
GetNext1(str,next);
int i;
printf( " Test case #%d\n " ,T);
for (i = 2 ;i <= len;i ++ )
{
if (next[i] != 0 && i % (i - next[i]) == 0 ) // 保证不是原串且循环
{
printf( " %d %d\n " ,i,i / (i - next[i]));
}
}
printf( " \n " );
}
return 0 ;
}
http://poj.org/problem?id=2406
POJ 2406 Power Strings
大意:给出一个字符串S,求该字符串最多是由相同重复字串连接而成的
若S由n个A组成,则称 S = A^n,求最大的n
如 S=aaa,S="a"^3 => n = 3;
S=ababa => n = 1
分析:KMP
与POJ 1961类似,而且更简单:
若L%(L-next[L])==0,n = L/(L-next[L]),else n = 1
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
stdio.h
>
#include < string .h >
const int N = 1000000 + 10 ;
char str[N];
int next[N];
int len;
void GetNext1( char str[N], int next[N]) // 寻找模式串的粗略next
{
int l = strlen(str);
next[ 0 ] =- 1 ;
int i = 0 ,j =- 1 ;
while (i < l)
{
if (j ==- 1 || str[i] == str[j])
{
i ++ ;j ++ ;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
int T = 0 ;
while (scanf( " %s " ,str) != EOF)
{
if (strcmp(str, " . " ) == 0 ) break ;
GetNext1(str,next);
int len = strlen(str);
if (len % (len - next[len]) == 0 )
printf( " %d\n " ,len / (len - next[len]));
else
printf( " 1\n " );
}
return 0 ;
}
#include < string .h >
const int N = 1000000 + 10 ;
char str[N];
int next[N];
int len;
void GetNext1( char str[N], int next[N]) // 寻找模式串的粗略next
{
int l = strlen(str);
next[ 0 ] =- 1 ;
int i = 0 ,j =- 1 ;
while (i < l)
{
if (j ==- 1 || str[i] == str[j])
{
i ++ ;j ++ ;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
int T = 0 ;
while (scanf( " %s " ,str) != EOF)
{
if (strcmp(str, " . " ) == 0 ) break ;
GetNext1(str,next);
int len = strlen(str);
if (len % (len - next[len]) == 0 )
printf( " %d\n " ,len / (len - next[len]));
else
printf( " 1\n " );
}
return 0 ;
}
http://poj.org/problem?id=2752
POJ 2752 Seek the Name, Seek the Fame
大意:
给出一个字符串A,求A有多少个前缀同时也是后缀,从小到大输出这些前缀的长度
分析:KMP
对于长度为len的字符串,由next的定义知:
A[0]A[1]...A[next[len]-1]=A[len-next[len]]...A[len-1]此时A[0]A[1]...A[next[len]-1]为一个符合条件的前缀
有A[0]A[1]....A[next[next[len]]-1] = A[len-next[next[len] - next[next[len]]]...A[next[len]-1],故A[0]A[1]....A[next[next[len]]-1]也是一个符合条件的前缀
故从len=>next[len]=>next[next[len]] ....=>直到某个next[]为0均为合法答案,注意当首位单词相同时,也为答案。
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
stdio.h
>
#include < string .h >
#include < vector >
using namespace std;
vector < int > ans;
const int N = 1000000 + 10 ;
char str[N];
int next[N];
void GetNext1( char str[N], int next[N]) // 寻找模式串的粗略next
{
int l = strlen(str);
next[ 0 ] =- 1 ;
int i = 0 ,j =- 1 ;
while (i < l)
{
if (j ==- 1 || str[i] == str[j])
{
i ++ ;j ++ ;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
while (scanf( " %d " , & str) != EOF)
{
scanf( " %s " ,str);
GetNext1(str,next);
int cur,len;
len = strlen(str);
cur = len;
ans.clear();
while (cur)
{
ans.push_back(cur);
cur = next[cur];
}
if (str[ 0 ] == str[len]) // 首位字符相同
ans.push_back( 1 );
int sz = ans.size();
for (cur = sz - 1 ;cur > 0 ;cur -- )
printf( " %d " ,ans[cur]);
printf( " %d\n " ,ans[ 0 ]);
}
return 0 ;
}
#include < string .h >
#include < vector >
using namespace std;
vector < int > ans;
const int N = 1000000 + 10 ;
char str[N];
int next[N];
void GetNext1( char str[N], int next[N]) // 寻找模式串的粗略next
{
int l = strlen(str);
next[ 0 ] =- 1 ;
int i = 0 ,j =- 1 ;
while (i < l)
{
if (j ==- 1 || str[i] == str[j])
{
i ++ ;j ++ ;
next[i] = j;
}
else
j = next[j];
}
}
int main()
{
while (scanf( " %d " , & str) != EOF)
{
scanf( " %s " ,str);
GetNext1(str,next);
int cur,len;
len = strlen(str);
cur = len;
ans.clear();
while (cur)
{
ans.push_back(cur);
cur = next[cur];
}
if (str[ 0 ] == str[len]) // 首位字符相同
ans.push_back( 1 );
int sz = ans.size();
for (cur = sz - 1 ;cur > 0 ;cur -- )
printf( " %d " ,ans[cur]);
printf( " %d\n " ,ans[ 0 ]);
}
return 0 ;
}
![2011031513160129.jpg](https://i-blog.csdnimg.cn/blog_migrate/56afc4da7c771e113b8b008fa9f3b360.jpeg)