Description
有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。
Input
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。
第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。
Output
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 1,000,000,007 取模的结果。
Sample Input
样例输入1:
6 3 1
aabaab
aab
样例输入2:
6 3 2
aabaab
aab
Sample Output
样例输出1:
2
样例输出2:
7
Hint
样例解释:
所有合法方案如下:(加下划线的部分表示取出的子串)
样例一:aab aab / aab aab
样例二:a ab aab / a aba ab / a a ba ab / aab a ab / aa b aab / aa baa b / aab aa b
样例三:a a b aab / a a baa b / a ab a a b / a aba a b / a a b a a b / a a ba a b / aab a a b
数据范围:
对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;
对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2;
对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m;
对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m;
对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m;
对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。
Source
NOIP2015,动态规划
Solution
先用三维的数组来考虑
如果用f[i][j][k]表示选择a子串的第i为后,在a串前i位,b串前j位选择k个子串的组合方案;
用s[i][j][k]表示在a串前i位,b串前j位选择k个子串的组合方案;
二者的区别即为f选了第i位,而s不确定是否选
对于f数组的状态显然有:f[i][j][k] = f[i - 1][j - 1][k] + s[i - 1][j - 1][k - 1](a[i] == b[j]);f[i][j][k] == 0(a[i] != b[j]);
对于s数组的状态有:s[i][j][k] = f[i][j][k] + s[i - 1][j][k];
显然对与两个数组只有第i - 1号会有影响,所以便可以将第一维压缩掉
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L 200 + 10
#define mod 1000000007
#define LL long long
using namespace std;
int n, m, k;
int dp[L][L], f[L][L];
char a[1050], b[L];
int main() {
freopen("substring.in", "r", stdin);
freopen("substring.out", "w", stdout);
scanf("%d %d %d", &n, &m, &k);
scanf("%s %s", a + 1, b + 1);
dp[0][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = m; j >= 1; --j) {
if (a[i] == b[j])
for (int l = min(k, j); l >= 1; --l)
f[j][l] = (f[j - 1][l] + dp[j - 1][l - 1]) % mod, dp[j][l] = (dp[j][l] + f[j][l]) % mod;
else for (int l = 1; l <= min(k, j); ++l) f[j][l] = 0;
}
printf("%d\n", dp[m][k]);
return 0;
}
Summary
这是考试的题目
考试的时候只有10分,完全没有想到转移方程,就写了一个KMP骗分
后面对着玄学题解想了很久的转移方程——表示对于两个数组真的想不到啊
总算拼拼凑凑找出了转移方程,结果实现的时候忘记从数组第一位开始存字符,WA了一次,然后就A了