Description
Input
第一行为字符串A。
第二行为字符串B。
Output
输出在B的所有循环同构串中,有多少个能够与A匹配。
Sample Input
输入1:
aaaa
aaaa
输入2:
a*a
aaaaaa
输入3:
* a*b*c *
abacabadabacaba
Sample Output
输出1:
4
输出2:
6
输出3:
15
Data Constraint
对于30%的数据,M<=20;
对于80%的测试点,M<=200;
对于100%的测试点,1<=N<=100,1<=M<=100000。
Solution
30%随便爆搜
80%发现
O(n3)
甚至更多一点都能过,那么就准备好有一点水准的暴力
分析题目,可以发现,实质上就是字符串A被
∗
分成若干个小字符串,每个小字符串要按顺序分别与字符串B匹配即可。不过,如果前后不是
先把B复制一份,然后可以用两个指针i和j,分别指着A的开头和枚举的B的开头,一个个做,以
∗
为分界点。如果当前字符匹配成功,就把i+1,j+1。如果当前字符匹配失败,就把i还原到这一个小字符串的开头,j变成这次匹配之前的位置+1,知道i超过A的长度或j超过应到达的地方就结束。
最后,只有i和j都超过了结尾,才能算一个匹配成功。
100%
有一种DP的做法,但是我用的是80分的爆搜加个优化。
B已经被复制。
A串被
∗
分割之后,从1开始给每个小字符串标号。用一个预处理F[i,j]表示字符串B从i这个字符之后,第j个小字符串最早从B串的哪个位置开始。那么每次就只用跳到对应的位置就行了,如果已经跳过了n个位置,却还没有把所有小字符串做完,就不可行。单次匹配时间复杂度降为
怎么预处理F呢?思考一下要做的是什么。在一个字符串里面匹配字符串。很显然,用KMP就行了。KMP模板
另:调试时不要相信PASCAL
Code
var
n,i,j,k,kk,ans,m,l,q,jy,jy2:longint;
t,s,s1:ansistring;
ch:char;
bz,bz2:boolean;
next,long:array[1..110] of longint;
a:array[1..200020,1..110] of longint;
procedure getnext(s:ansistring);
var
i,j,n:longint;
begin
n:=length(s);j:=0;
for i:=2 to n do
begin
while (j>0)and(s[i]<>s[j+1]) do j:=next[j];
if (s[i]=s[j+1]) then inc(j);
next[i]:=j;
end;
end;
procedure kmp(s:ansistring;k:longint);
var
m,i,j:longint;
begin
j:=0;m:=length(s);
for i:=2 to 2*n do
begin
while (j>0)and(t[i]<>s[j+1]) do j:=next[j];
if (t[i]=s[j+1]) then inc(j);
if j=m then begin a[i-long[k]+1,k]:=i-long[k]+1;j:=next[j];end;
end;
end;
begin
readln(s);readln(t);
m:=length(s);n:=length(t);t:=t+t;s:=s+'!';t:=t+'@';i:=1;kk:=0;
while i<=m do
begin
s1:='';while (s[i]='*')and(i<=m) do inc(i);
while (s[i]<>'*')and(i<=m) do begin s1:=s1+s[i];inc(i);end;
if (i<=m) then
begin
fillchar(next,sizeof(next),0);getnext(s1);
inc(kk);long[kk]:=length(s1);kmp(s1,kk);
end;
end;
for i:=1 to kk do
begin
for j:=2*n downto 1 do
begin
if (j=2*n)and(a[j,i]=0) then a[j,i]:=2*n+1;
if a[j,i]=0 then a[j,i]:=a[j+1,i];
end;
end;
for i:=1 to n do
begin
bz:=true;
j:=1;k:=i;q:=kk;l:=i+n-1;
if (s[m]<>'*') then
begin
while (s[m+l-i-n+1]<>'*')and(l>=k) do
begin
if s[m+l-i-n+1]=t[l] then dec(l)
else begin bz:=false;break;end;
end;
dec(q);
end;
if (s[1]<>'*') then
begin
while (s[k-i+1]<>'*')and(k<=l) do
begin
if s[k-i+1]=t[k] then inc(k)
else begin bz:=false;break;end;
end;
inc(j);
end;
if bz=false then continue;
while (j<=q)and(k<=l) do
begin
k:=a[k,j]+long[j];inc(j);
end;
if (bz)and(j>q)and(k<=l+1) then inc(ans);
end;
writeln(ans);
end.