Description
某日mhy12345在教同学们写helloworld,要求同学们用程序输出一个给定长度的字符串,然而发现有些人输出了一些“危险”的东西,所以mhy12345想知道对于任意长度 n n 的小写字母字符串,不包含危险串的字符串个数
Input
多组数据,以 EOF E O F 结束。对于每组数据,第一行一个数 n n ,表示字符串的长度,第二行一个字符串 str s t r 表示危险串。
Output
对于每组数据,输出一个整数表示答案 mod(109+7) m o d ( 10 9 + 7 ) 的值。
Sample Input
5
a
Sample Output
9765625
Data Constraint
对于
10%
10
%
的数据,
|str|=1
|
s
t
r
|
=
1
对于另
30%
30
%
的数据,
n≤5
n
≤
5
对于另
30%
30
%
的数据,危险串不存在相同字符
对于
100%
100
%
的数据,
0≤|str|≤100,0≤n≤10000
0
≤
|
s
t
r
|
≤
100
,
0
≤
n
≤
10000
Solution
考试时想过用容斥,但好像不可做……所以就换了一种方式——DP
设状态
f[i,j]
f
[
i
,
j
]
为当前已经做到第i位,已匹配了前j位危险串的合法方案数。
那么对于不存在相同字符的串就有如下转移:
当下一位选
S[j+1]
S
[
j
+
1
]
时,转移到
f[i,j+1]
f
[
i
,
j
+
1
]
。
当下一位选
S[1]
S
[
1
]
时,转移到
f[i,1]
f
[
i
,
1
]
。
选其它,转移到
f[i,0]
f
[
i
,
0
]
对于存在相同字符的串,那就稍微有些不同了。
。由于给定串可能包含重复字母,因此
下一位不选
s[j+1]
s
[
j
+
1
]
时,不一定转移到
f[i,0]
f
[
i
,
0
]
,而是可能转移到
f[i][next[j]+1]
f
[
i
]
[
n
e
x
t
[
j
]
+
1
]
、
f[i][next[next[j]]+1]
f
[
i
]
[
n
e
x
t
[
n
e
x
t
[
j
]
]
+
1
]
、
f[i][next[next[next[j]]]+1]
f
[
i
]
[
n
e
x
t
[
n
e
x
t
[
n
e
x
t
[
j
]
]
]
+
1
]
……其中
next 数组是 kmp 的 next 数组,具体转移到哪个要
看下一位具体选什么。
所以我们预处理一个p[j,k]数组,表示选j字符最多可以匹配到第几位。反之如果不匹配到最多的那一位就有可能提前匹配了一个危险串,就会有不合法的可能。
所以就有
f[i+1,p[j,k]]+=f[i,j]
f
[
i
+
1
,
p
[
j
,
k
]
]
+
=
f
[
i
,
j
]
Code
一个 90 90 分代码,求找bug。
const mo=1000000007;
var m,i,j,k:longint;
n,ans:int64;
c:array[1..26] of char;
p:array[0..105,1..26] of longint;
next:array[1..105] of longint;
f:array[0..10005,0..105] of int64;
s:string;
function min(x,y:longint):longint;
begin
if x<y then exit(x);exit(y);
end;
begin
for i:=1 to 26 do c[i]:=chr(ord('a')+i-1);
while not eof do begin
readln(n);
readln(s);
m:=length(s);ans:=0;
fillchar(next,sizeof(next),0);
fillchar(p,sizeof(p),0);
fillchar(f,sizeof(f),0);
for i:=2 to m 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;
for i:=0 to m-1 do begin
for j:=1 to 26 do begin
k:=i;
while (k<>0) and (c[j]<>s[k+1]) do k:=next[k];
if c[j]=s[k+1] then k:=k+1;
p[i,j]:=k;
end;
end;
for i:=0 to n-1 do begin
for j:=0 to min(m-1,i) do begin
for k:=1 to 26 do begin
f[i+1,p[j,k]]:=(f[i+1,p[j,k]]+f[i,j]) mod mo;
end;
end;
end;
for i:=0 to m-1 do ans:=(ans+f[n,i]) mod mo;
writeln(ans);
end;
end.