问题描述
有两个仅包含小写英文字母的字符串 A 和 B。
现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B 相等?
注意:子串取出的位置不同也认为是不同的方案。
输入格式
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。
第二行包含一个长度为 n 的字符串,表示字符串 A。
第三行包含一个长度为 m 的字符串,表示字符串 B。
输出格式
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 1,000,000,007 取模的结果。
样例输入
#1
6 3 1
aabaab
aab
#2
6 3 2
aabaab
aab
#3
6 3 3
aabaab
aab
样例输出
#1
2
#2
7
#3
7
数据范围
题解
K个子串互不重叠,但是是可以相连的,也就是说,一个长度为2的子串,可以看成两个长度为1的子串相连。
f[i][j][k][0/1]表示A的前i个字符选出k个子串得到B的前j个字符,其中,0表示A[i]不选,1表示A[i]要选。
当A[i]==B[i]时,
f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]
f[i][j][k][1]=f[i-1][j-1][k][1]+f[i-1][j-1][k-1][1]+f[i-1][j-1][k-1][0]
当A[i]!=B[i]时
f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]
f[i][j][k][1]=0
(上面方程看懂的自动跳过这段)
**********************************************************************************************************
当A[i]==B[i]时
如果A[i]不选,那么B[j]必定从A的前i-1个字符中取,方案数为前i-1个字符选和不选的总和,即f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]
如果A[i]选,如果A[i-1]选,A[i]可以选择接在上一个子串的后面,或者自己作为下一个子串的第一个字符,如果A[i-1]不选,显然A[i]只能作为下一个子串的第一个字符,以上三种方案加起来,就是选A[i]的方案数,即f[i][j][k][1]=f[i-1][j-1][k][1]+f[i-1][j-1][k-1][1]+f[i-1][j-1][k-1][0]
当A[i]!=B[i]时
如果A[i]不选,情况同上,f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1]
由于A[i]!=B[i],A[i]选不了,f[i][j][k][1]=0
**********************************************************************************************************
考虑数组的大小,要开到1000×200×200×2=8×107,而通常开两三个1×107的数组就面临MTE的风险了。
注意到f[i]只和f[i-1]有关,于是滚动数组压掉一维。
1 #include <cstring> 2 #include <cstdio> 3 const int maxn=1e9+7; 4 int n,m,K,f[2][205][205][2]; 5 char a[1005],b[205]; 6 int main() 7 { 8 int i,j,k; 9 scanf("%d%d%d",&n,&m,&K); 10 scanf("%s",a+1); 11 scanf("%s",b+1); 12 f[1][0][0][0]=f[0][0][0][0]=1; 13 for (i=1;i<=n;i++) 14 for (j=1;j<=m;j++) 15 for (k=1;k<=K;k++) 16 if (a[i]==b[j]) 17 f[i&1][j][k][0]=(f[(i-1)&1][j][k][0]+f[(i-1)&1][j][k][1])%maxn, 18 f[i&1][j][k][1]=(1ll*f[(i-1)&1][j-1][k][1]+f[(i-1)&1][j-1][k-1][1]+f[(i-1)&1][j-1][k-1][0])%maxn; 19 else 20 f[i&1][j][k][0]=(f[(i-1)&1][j][k][0]+f[(i-1)&1][j][k][1])%maxn, 21 f[i&1][j][k][1]=0; 22 printf("%d",(f[n&1][m][K][0]+f[n&1][m][K][1])%maxn); 23 return 0; 24 }