【NOIP2015Day2T2】【洛谷P2679】子串

问题描述

有两个仅包含小写英文字母的字符串 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 }
原文地址:https://www.cnblogs.com/rabbit1103/p/9817263.html