[Luogu P2679] [UOJ 149] [NOIP 2015 tg] 子串

版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/82975205

洛谷传送门

UOJ传送门

题目描述

有两个仅包含小写英文字母的字符串 A A B B

现在要从字符串 A A 中取出 k k 个互不重叠的非空子串,然后把这 k k 个子串按照其在字符串 A A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B B 相等?

注意:子串取出的位置不同也认为是不同的方案。

输入输出格式

输入格式:

第一行是三个正整数 n , m , k n,m,k ,分别表示字符串 A A 的长度,字符串 B B 的长度,以及问题描述中所提到的 k k ,每两个整数之间用一个空格隔开。

第二行包含一个长度为 n n 的字符串,表示字符串 A A

第三行包含一个长度为 m m 的字符串,表示字符串 B B

输出格式:

一个整数,表示所求方案数。

由于答案可能很大,所以这里要求输出答案对 1000000007 1000000007 取模的结果。

输入输出样例

输入样例#1:

6 3 1 
aabaab 
aab

输出样例#1:

2

输入样例#2:

6 3 2 
aabaab 
aab

输出样例#2:

7

输入样例#3:

6 3 3 
aabaab 
aab

输出样例#3:

7

说明

img

对于第 1 组数据: 1 n 500 , 1 m 50 , k = 1 1≤n≤500,1≤m≤50,k=1 ;
对于第 2 组至第 3 组数据: 1 n 500 , 1 m 50 , k = 2 1≤n≤500,1≤m≤50,k=2 ;
对于第 4 组至第 5 组数据: 1 n 500 , 1 m 50 , k = m 1≤n≤500,1≤m≤50,k=m ;
对于第 1 组至第 7 组数据: 1 n 500 , 1 m 50 , 1 k m 1≤n≤500,1≤m≤50,1≤k≤m ;
对于第 1 组至第 9 组数据: 1 n 1000 , 1 m 100 , 1 k m 1≤n≤1000,1≤m≤100,1≤k≤m ;
对于所有 10 组数据: 1 n 1000 , 1 m 200 , 1 k m 1≤n≤1000,1≤m≤200,1≤k≤m

解题分析

d p [ k ] [ i ] [ j ] dp[k][i][j] 表示已经分了 k k 段, A A 串匹配到 i i B B 串恰好匹配到 j j 的方案数, 当 A [ i ] = B [ j ] A[i]=B[j] 的时候有
d p [ k ] [ i ] [ j ] = i = 1 j 1 d p [ k 1 ] [ i ] [ j 1 ] dp[k][i][j]=\sum_{i=1}^{j-1}dp[k-1][i][j-1]
如果 A [ i 1 ] = B [ j 1 ] A[i-1]=B[j-1] 的话, d p [ k ] [ i ] [ j ] dp[k][i][j] 还要加上 d p [ k ] [ i 1 ] [ j 1 ] dp[k][i-1][j-1] , 等于合并成一个区间的方案。

然后我们发现上面的那个式子就是个前缀和, 直接处理出来, 而且整个方程只和 k , k 1 k,k-1 有关, 所以滚动一维。

代码如下:

#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]);
}

猜你喜欢

转载自blog.csdn.net/LPA20020220/article/details/82975205