洛谷传送门
UOJ传送门
题目描述
有两个仅包含小写英文字母的字符串 和 。
现在要从字符串 中取出 个互不重叠的非空子串,然后把这 个子串按照其在字符串 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 相等?
注意:子串取出的位置不同也认为是不同的方案。
输入输出格式
输入格式:
第一行是三个正整数 ,分别表示字符串 的长度,字符串 的长度,以及问题描述中所提到的 ,每两个整数之间用一个空格隔开。
第二行包含一个长度为 的字符串,表示字符串 。
第三行包含一个长度为 的字符串,表示字符串 。
输出格式:
一个整数,表示所求方案数。
由于答案可能很大,所以这里要求输出答案对 取模的结果。
输入输出样例
输入样例#1:
6 3 1
aabaab
aab
输出样例#1:
2
输入样例#2:
6 3 2
aabaab
aab
输出样例#2:
7
输入样例#3:
6 3 3
aabaab
aab
输出样例#3:
7
说明
对于第 1 组数据:
;
对于第 2 组至第 3 组数据:
;
对于第 4 组至第 5 组数据:
;
对于第 1 组至第 7 组数据:
;
对于第 1 组至第 9 组数据:
;
对于所有 10 组数据:
。
解题分析
设
表示已经分了
段,
串匹配到
,
串恰好匹配到
的方案数, 当
的时候有
如果
的话,
还要加上
, 等于合并成一个区间的方案。
然后我们发现上面的那个式子就是个前缀和, 直接处理出来, 而且整个方程只和 有关, 所以滚动一维。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#define R register
#define IN inline
#define W while
#define File freopen("t2.in", "r", stdin), freopen("t2.out", "w", stdout)
#define gc getchar()
#define ll long long
#define MOD 1000000007
#define MX 1050
int dp[2][MX][205];
int sum[MX][205];
char buf1[MX], buf2[MX];
int n, m, tim;
int main(void)
{
R int i, j, k, cur = 0, pre;
scanf("%d%d%d", &n, &m, &tim);
scanf("%s%s", buf1 + 1, buf2 + 1);
buf1[0] = '#', buf2[0] = '$';
for (j = 0; j <= n; ++j)
sum[j][0] = 1;
for (i = 1; i <= tim; ++i)
{
pre = cur, cur ^= 1;
std::memset(dp[cur], 0, sizeof(dp[cur]));
for (j = 1; j <= n; ++j)
for (k = 1; k <= m; ++k)
{
if(buf1[j] == buf2[k])
{
dp[cur][j][k] = sum[j - 1][k - 1];
if(buf1[j - 1] == buf2[k - 1]) (dp[cur][j][k] += dp[cur][j - 1][k - 1]) %= MOD;
}
}
std::memset(sum, 0, sizeof(sum));
for (j = 1; j <= n; ++j)
for (k = 1; k <= m; ++k)
sum[j][k] = (sum[j - 1][k] + dp[cur][j][k]) % MOD;
}
for (i = 1; i <= n; ++i) dp[cur][i][m] = (dp[cur][i - 1][m] + dp[cur][i][m]) % MOD;
printf("%d", dp[cur][n][m]);
}