题目描述
有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。
输入
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。 第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。
输出
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 1,000,000,007 取模的结果。
样例输入
样例输出
HINT
这题在推出状态后转移时竟然改变了状态的意义,吐血地打了1个小时。
下面要郑重地写一下状态。
f[i][j][k]表示B串的1~i已被A串的1~j匹配完,此时匹配了k个子串,且A串的第j位匹配B串的第i位,此时的方案数。
则f[i][j][k]=f[i-1][1~j-1][k-1]+f[i-1][j-1][k];前提是a[j]=b[i].
但这样的转移是O(nm^2k)的,还是会超时
所以我们可以记下来f[i-1][1~j-1][k-1] 的和啊。
这样转移就是O(1)的了,再开一维滚动防止爆内存。时间复杂度O(nmk).
这才将这题解决,可是考试时在这题上花了太多时间qwq,记住吧。
var mo,n,m,k,i,j,p,now,pre,s:longint;ans:int64;a,b:ansistring;
f:array[0..1,0..1000,0..1000]of longint;
begin
mo:=1000000007;
readln(n,m,k);
readln(a);
readln(b);
for i:=1 to n do if a[i]=b[1] then f[0][i][1]:=1;
for p:=2 to m do
begin
pre:=1-now;
for j:=1 to k do
begin
s:=0;
for i:=1 to n do
begin
s:=(s+f[now,i-1,j-1])mod mo;
if a[i]=b[p] then f[pre][i][j]:=(f[now][i-1][j]+s)mod mo
else f[pre][i][j]:=0;
end;
end;
now:=pre;
end;
for i:=1 to n do ans:=(ans+f[now][i][k])mod mo;
writeln(ans);
end.