Description
对于一个序列????[1], ????[2], … , ????[????],其子序列为一序列????[1], ????[2], … , ????[????],满 足1 ≤ ????[1] < ????[2] < ⋯ < ????[????] ≤ ????, 1 ≤ ???? ≤ ????。????的两个子序列????, ????是不同的,当 且其长度不同,或存在一个位置????,满足????[????] ≠ ????[????]。
给定两个长度分别为????, ????的序列????, ????,定义序列二元组(????, ????)是好的,当且 仅当满足
-
????为????的子序列且????为????的子序列
-
????, ????长度相同
-
对于所有的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;
}