先kmp匹配一遍
设s的下标为1~n
则当
i
%
(
1
−
n
x
t
i
)
=
0
i\%(1-nxt_i)=0
i%(1−nxti)=0时有
K
=
1
−
n
x
t
i
K=1-nxt_i
K=1−nxti的的答案
证明:
令
s
l
,
r
s_{l,r}
sl,r表示由第
l
l
l位到第
r
r
r位组成的字符串(inclusive)
令
l
e
n
=
i
−
n
x
t
i
len=i-nxt_i
len=i−nxti
由
n
x
t
nxt
nxt的定义可知
s
1
,
i
−
l
e
n
=
s
l
e
n
+
1
,
i
s_{1,i-len}=s_{len+1,i}
s1,i−len=slen+1,i
由于
i
%
l
e
n
=
0
i\%len=0
i%len=0
所以可以将
s
1
,
i
−
l
e
n
s_{1,i-len}
s1,i−len和
s
l
e
n
+
1
,
i
s_{len+1,i}
slen+1,i分别拆分为
i
l
e
n
−
1
\frac{i}{len}-1
leni−1个字符串,且分别相当
所以在
s
1
,
i
s_{1,i}
s1,i中每组
l
e
n
len
len长度的字符串相等,满足题意
并且这样一定是最优的(自行证明)
值得指出的一个性质是,一个字符串的任意循环元长度必然是最小循环元长度的倍数,证明留作读者思考。——《算法竞赛进阶指南》
对。试着说明:
在kmp匹配nxt数组时,我们是有“备选”选项的
while(j&&s[i-1]!=s[j+1-1])j=nxt[j];
若一个循环元的长度为l,则i-l必然为nxt_i的“备选”选项
nxt_i的备选选项有nxt_(nxt_i)等,写得清楚点形如
n
x
t
n
x
t
i
,
n
x
t
n
x
t
n
x
t
i
nxt_{nxt_i},nxt_{nxt_{nxt_i}}
nxtnxti,nxtnxtnxti
若其中有某个位置上的循环元长度不为len
则表示可以把a个长度为len的写成len个长度为a的(a,len互质)
这len个长度为a的串的第一个字符为s_a,s_2a%len,s_3a%len…s_len*a%len, 因为a,len互质,其实就是s_1,s_2,…s_len(并不一一对应)
这样就说明:长度为len的这个循环元每一位都相等!那么它一定可以再分,矛盾。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
char s[1000005];
int nxt[1000005];
int main()
{
int tot=0;
while(scanf("%d",&n)&&n)
{
scanf("%s",s);
printf("Test case #%d\n",++tot);
int n=strlen(s);
nxt[1]=0;
for(int i=2,j=0;i<=n;++i)
{
while(j&&s[i-1]!=s[j+1-1])j=nxt[j];
if(s[i-1]==s[j+1-1])++j;
nxt[i]=j;
}
for(int i=1;i<=n;++i)
{
if(nxt[i]&&i%(i-nxt[i])==0)printf("%d %d\n",i,i/(i-nxt[i]));
}
printf("\n");
}
return 0;
}