Description
给出p个长度不超过10的字符串,字符集大小为n。
如果这p个串都不是字符串s的子串,则认为s是幸运的。
求长度为m的幸运串个数。
Input
第一行三个正整数n,m,p。
第二行n个不同的字符,表示字符集,其ASCII码大于32。
接下来p行每行一个字符串,表示不允许被包含的串。
Output
一行一个整数,表示幸运串个数。
Sample Input
2 3 1
ab
bb
Sample Output
5
Data Constraint
对于20%的数据,m ≤ 6,n ≤ 10;
对于50%的数据,p个串的长度不超过4,m ≤ 50,n ≤ 10;
对于100%的数据,n ≤ 50,m ≤ 50,p ≤ 10。
Hint
aaa aab aba baa bab 共5个串为幸运串。
题解
这题首先我们看到找出p字符串不为子串的字符串方案数。
想到什么?AC_Automation of course
如果不会AC_Automation也就是AC自动机的话,先学学也可。
其实这玩意就是trie+kmp。
于是我们把p字符串建立一颗AC自动机,然后在结尾挂上一个标记(注意fail边要下传!!!)
接下来我们考虑DP
设表示当前建立新字符串建到第位时,AC自动机上走到了这个位置。
初始化
然后我们枚举走到了状态,再枚举当前位放第个字符。
然后跳fail链,跳到的位置记为。同时判断一下有没有走到标记即可
方程:
很清真,很简单。
然后出题人就硬是要你套个高精度加法。
时间复杂度:
代码
uses math;
var
i,j,k,l,n,m,p,tot:longint;
id:array[1..1000] of longint;
tree:array[0..5000,0..200] of longint;
d,next:array[0..50000] of longint;
an,ka,kb:array[1..200] of longint;
f:array[0..100,0..200] of ansistring;
bz:array[1..5000] of boolean;
s,c:string;
ans:ansistring;
function jia(a,b:ansistring):ansistring;
var
i,j,k,l,lena,lenb,len:longint;
c:ansistring;
begin
lena:=length(a);lenb:=length(b);
if (lena>lenb) or ((lena=lenb) and (a>b)) then
begin
c:=a;a:=b;b:=c;
l:=lena;lena:=lenb;lenb:=l;
end;
j:=1;for i:=1 to lena do begin ka[i]:=ord(a[j])-48; inc(j); end;
j:=1;for i:=1 to lenb do begin kb[i]:=ord(b[j])-48; inc(j); end;
an:=kb;
k:=0;j:=0;l:=lenb;
for i:=lena downto 1 do
begin
j:=ka[i]+kb[l]+k;
k:=j div 10;
j:=j mod 10;
an[l]:=j;
dec(l);
end;
c:='';
while k>0 do
begin
if l>0 then
begin
j:=kb[l]+k;
k:=j div 10;
j:=j mod 10;
an[l]:=j;
dec(l);
end
else
begin
c:=c+chr(k+48);
break;
end;
end;
for i:=1 to lenb do
begin
c:=c+chr(an[i]+48);
end;
exit(c);
end;
procedure build_ac_automation;
var
i,j,k,l,head,tail,took,x,y,dep:longint;
begin
head:=1;
tail:=1;
took:=1;
repeat
for dep:=head to tail do
begin
for i:=1 to n do
begin
if tree[d[dep],i]>0 then
begin
y:=tree[d[dep],i];
x:=next[d[dep]];
while (x>0) and (tree[x,i]=0) do x:=next[x];
if d[dep]>0 then
begin
next[y]:=tree[x,i];
end;
if y<>tree[x,i] then
begin
if bz[tree[x,i]] then bz[y]:=true;
end;
inc(took);
d[took]:=y;
end;
end;
end;
head:=tail+1;
tail:=took;
until head>tail;
end;
procedure trie(x,i,up:longint);
var
j,k,l:longint;
begin
if i=up then
begin
bz[x]:=true;
exit;
end;
if tree[x,id[ord(s[i+1])]]>0 then
begin
trie(tree[x,id[ord(s[i+1])]],i+1,up);
end
else
begin
inc(tot);
tree[x,id[ord(s[i+1])]]:=tot;
trie(tree[x,id[ord(s[i+1])]],i+1,up);
end;
end;
begin
//assign(input,'consored.in');reset(input);
readln(n,m,p);
readln(c);
tot:=0;
for i:=1 to n do
begin
inc(tot);
id[ord(c[i])]:=tot;
tree[0,tot]:=tot;
end;
for i:=1 to p do
begin
readln(s);
trie(0,0,length(s));
end;
build_ac_automation;
f[0,0]:='1';
for i:=1 to m do
begin
for j:=0 to tot do
begin
if (length(f[i-1,j])>0) then
begin
for k:=1 to n do
begin
l:=j;
while (l>0) and (tree[l,k]=0) do l:=next[l];
if not bz[tree[l,k]] then
begin
if (length(f[i,tree[l,k]])=0) then f[i,tree[l,k]]:='0';
f[i,tree[l,k]]:=jia(f[i,tree[l,k]],f[i-1,j]);
end;
end;
end;
end;
end;
for i:=1 to tot do
begin
ans:=jia(ans,f[m,i]);
end;
writeln(ans);
end.