POJ 2406(KMP中next的性質)
阿新 • • 發佈:2018-12-24
Power Strings
Description 給你一個字串a,問a最多由幾個完全相同的子串連線而成Input 每一個測試點都會給你一個長度為m(1<=m<=1000000)的字串,並以句號結尾。Output 輸出a最多由幾個完全相同的子串連線而成。Sample Input abcd aaaa ababab . Sample Output 1 4 3 Hint 用cin會TSource |
這題要用到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.