Power Strings
Description
给你一个字符串a,问a最多由几个完全相同的子串连接而成
Input
每一个测试点都会给你一个长度为m(1<=m<=1000000)的字符串,并以句号结尾。
Output
输出a最多由几个完全相同的子串连接而成。
Sample Input abcd aaaa ababab . Sample Output 1 4 3 Hint
用cin会T
Source |
这题要用到KMP算法中next的性质……我研究了一上午才搞懂
一个字母的next表示这个字母要向后跳到哪一位才能与原字符串匹配
a b c a b c
0 0 0 1 2 3
释义:第2个a=1->若不匹配可跳到第一个字符为起点(0表示完全不匹配)
经过观察发现
abcabcabc
000123456
a a i a a i a a i
0 10 1 2 3 4 5 6
于是发现next函数的嵌套关系:
L1-L2
L1-L2 L3-L4
于是如果一个字符串是循环的,那么最后的next正好就应该指向循环的那个圈
即便本身有自带的链也满足,观察下图即可当证明了:
Program PowerString;
const
maxn=10000010;
var
n,i,j,duan_luo:longint;
next:array[0..maxn] of longint;
a,b:ansistring;
function check:boolean;
var
i,j:longint;
begin
if (n mod duan_luo>0) then exit(false);
for i:=duan_luo+1 to n do if (a[i]<>a[i-duan_luo]) then exit(false);
exit(true);
end;
begin
while not eof do
begin
readln(a);
if a='.' then break;
n:=length(a);
j:=0; i:=1; next[1]:=0;
while (i<n) do
begin
if (j=0) or (a[i]=a[j]) then
begin
inc(i);inc(j);
if (a[i]<>a[j]) then next[i]:=next[j]
else next[i]:=j;
end
else j:=next[j];
end;
duan_luo:=n-next[i];
if check then writeln(n div duan_luo) else writeln(1);
end;
end.
代码2(前面的next总觉得有问题,于是我自行修改):
Program PowerString;
const
maxn=10000010;
var
n,i,j,duan_luo:longint;
next:array[0..maxn] of longint;
a,b:ansistring;
function check:boolean;
var
i,j:longint;
begin
if (n mod duan_luo>0) then exit(false);
for i:=duan_luo+1 to n do if (a[i]<>a[i-duan_luo]) then exit(false);
exit(true);
end;
begin
while not eof do
begin
readln(a);
if a='.' then break;
n:=length(a);
j:=0; i:=1; next[1]:=0;
while (i<n) do
begin
if (j=0) or (a[i]=a[j]) then
begin
inc(i);inc(j);
// if (a[i]<>a[j]) then next[i]:=next[j]
while (j>0) and (a[i]<>a[j]) do j:=next[j];
next[i]:=j;
end
else j:=next[j];
end;
duan_luo:=n-next[i];
if check then writeln(n div duan_luo) else writeln(1);
end;
end.
代码3:(最后那个if好像就用不着了……):
Program PowerString;
const
maxn=10000010;
var
n,i,j,duan_luo:longint;
next:array[0..maxn] of longint;
a,b:ansistring;
function check:boolean;
var
i,j:longint;
begin
if (n mod duan_luo>0) then exit(false);
for i:=duan_luo+1 to n do if (a[i]<>a[i-duan_luo]) then exit(false);
exit(true);
end;
begin
while not eof do
begin
readln(a);
if a='.' then break;
n:=length(a);
j:=0; i:=1; next[1]:=0;
while (i<n) do
begin
inc(i);inc(j);
//if (a[i]<>a[j]) then next[i]:=next[j]
while (j>0) and (a[i]<>a[j]) do j:=next[j];
next[i]:=j;
end;
duan_luo:=n-next[i];
if check then writeln(n div duan_luo) else writeln(1);
end;
end.
代码4:这层while有有只递增i,感觉没必要:
Program PowerString;
const
maxn=10000010;
var
n,i,j,duan_luo:longint;
next:array[0..maxn] of longint;
a,b:ansistring;
function check:boolean;
var
i,j:longint;
begin
if (n mod duan_luo>0) then exit(false);
for i:=duan_luo+1 to n do if (a[i]<>a[i-duan_luo]) then exit(false);
exit(true);
end;
begin
while not eof do
begin
readln(a);
if a='.' then break;
n:=length(a);
j:=0; i:=1; next[1]:=0;
for i:=2 to n do
begin
inc(j);
//if (a[i]<>a[j]) then next[i]:=next[j]
while (j>0) and (a[i]<>a[j]) do j:=next[j];
next[i]:=j;
end;
duan_luo:=n-next[i];
if check then writeln(n div duan_luo) else writeln(1);
end;
end.