Description

对于一个序列????[1], ????[2], … , ????[????],其子序列为一序列????[1], ????[2], … , ????[????],满 足1 ≤ ????[1] < ????[2] < ⋯ < ????[????] ≤ ????, 1 ≤ ???? ≤ ????。????的两个子序列????, ????是不同的,当 且其长度不同,或存在一个位置????,满足????[????] ≠ ????[????]。

给定两个长度分别为????, ????的序列????, ????,定义序列二元组(????, ????)是好的,当且 仅当满足

  1. ????为????的子序列且????为????的子序列

  2. ????, ????长度相同

  3. 对于所有的1 ≤ ???? ≤ ????的长度,满足????[????[????]] = ????[????[????]]

    两个二元组(????, ????), (????, ????)是不同的,当且仅当???? ≠ ????或???? ≠ ????。 现在希望你求出最大的????,满足存在二元组(????, ????)使得????的长度为????且(????, ????)是 好的。并求出满足长度为????的好的二元组的对数。答案对1e9+ + 7取模。

Input Format

包含两行字符串,分别表示序列????, ????。

Output Format

包含两行。 第一行为????。 第二个行为合法的二元组的对数对1e9 + 7取模的结果

Hint

对应100%的数据,????, ???? ≤ 5000,保证序列只包含小写字母。

Solution

那么显然,这是一道动规题,在LCS的基础加上了求方案数

考试的时候只想出了求LCS,后面的方案数就完。。。全没想出来

关于LCS就一个数组f[i][j]表示A串前i个,B串前j个的LCS,

那么f[i][j]=max(f[i-1][j],f[i][j-1]),且当A[i]==B[i]时,f[i][j]=max(f[i-1][j-1]+1)

那么怎么求方案数呢?

首先设一个数组g[i][j]表示对于A串前i个,B串前j个的LCS的方案数,

那么就有,

f[i][j] = f[i - 1][j];
g[i][j] = g[i - 1][j];
if (f[i][j - 1] == f[i][j])
	g[i][j] += g[i][j - 1];
else if (f[i][j - 1] > f[i][j]) {
	f[i][j] = f[i][j - 1];
	g[i][j] = g[i][j - 1];
}
if (A[i - 1] == B[j - 1])
	if (f[i - 1][j - 1] + 1 > f[i][j]) {
		f[i][j] = f[i - 1][j - 1] + 1;
		g[i][j] = g[i - 1][j - 1];
	} else if (f[i - 1][j - 1] + 1 == f[i][j])
		g[i][j] += g[i - 1][j - 1];

其实也不难想到这样的转移,但只是这样会出问题,

比如A=“abcd",B="abef",g[4][4]会等于g[3][4]+g[4][3]=2,这显然是错误的,

我们发现,g[3][4]=g[3][3]+g[2][4],g[4][3]=g[3][3]+g[4][2],我们这里的g[3][3]是不必算两次,

也就是说这里的g[3][3]重复计算了一次,

但并不是每个转移都是这样,条件如下,

if (f[i - 1][j - 1] == f[i][j] && f[i - 1][j] == f[i][j - 1])
	g[i][j] -= g[i - 1][j - 1];

不再多说了,

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 5012
using namespace std;

const int yh = 1e9 + 7;
int n, m, f[N][N];
long long g[N][N];
char A[N], B[N];

int main()
{
	scanf("%s\n%s", A, B);
	n = strlen(A), m = strlen(B);
	for (int i = 0; i <= n; ++i) g[i][0] = 1;
	for (int i = 0; i <= m; ++i) g[0][i] = 1;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j) {
			f[i][j] = f[i - 1][j];
			g[i][j] = g[i - 1][j];
			if (f[i][j - 1] == f[i][j])
				g[i][j] = (g[i][j] + g[i][j - 1]) % yh;
			else if (f[i][j - 1] > f[i][j]) {
				f[i][j] = f[i][j - 1];
				g[i][j] = g[i][j - 1];
			}
			if (A[i - 1] == B[j - 1]) {
				if (f[i - 1][j - 1] + 1 > f[i][j]) {
					f[i][j] = f[i - 1][j - 1] + 1;
					g[i][j] = g[i - 1][j - 1];
				} else if (f[i - 1][j - 1] + 1 == f[i][j])
					g[i][j] += g[i - 1][j - 1] % yh;
			}
			if (f[i - 1][j - 1] == f[i][j] && f[i - 1][j] == f[i][j - 1])
				g[i][j] -= g[i - 1][j - 1];
		}
	printf("%d\n", f[n][m]);
	printf("%d\n", (g[n][m] % yh + yh) % yh);
	return 0;
}

相关文章:

  • 2022-01-20
  • 2021-07-07
  • 2021-11-27
  • 2021-11-18
  • 2022-12-23
  • 2022-12-23
  • 2022-02-28
  • 2022-03-03
猜你喜欢
  • 2021-11-11
  • 2021-12-13
  • 2021-08-14
  • 2021-09-21
  • 2022-12-23
  • 2021-06-26
  • 2021-08-04
相关资源
相似解决方案