题目翻译(出自洛谷AT_abc130_e [ABC130E])
给出两个长度分别为N和M的整数序列S和T,它们均由 \(1\) 到 \(10^5\)(含 \(10^5\) )之间的整数组成。
求在S子序列和T子序列中,有多少对两个子序列的内容相同。
子序列的说明:
A的子序列是指通过从A删除零个或多个元素而不改变顺序而获得的序列。
对于S和T而言,如果子序列的内容相同,但是被删除元素的索引集(位置)不同,也当成两个不同的子序列。
输出答案模 109+7 的结果
分析
就本人少之又少的线性dp刷题量而言,这种涉及公共子序列的问题,转移方程的条件一般都是 \(s_i = t_ j\) 转移状态一般都是两个序列的前 \(i\) 和前 \(j\) 元素,即 \(f_{i, j}\) 表示 \(s[: i]\),\(t[: j]\) 的公共部分,在此题即 \(s[: i]\)和\(t[: j]\)的相同子序列个数。
设\(P(s_x)\) 是 \(s[:x-1]\)增加 \(s _x\)对 \(f _{x-1, y-1}\) 的影响,同理 \(t _y\);
\(P(s_x,t_y)\) 是 \(s[:x-1]\),\(t[:y-1]\) 增加 \(\{s _x\),\(t _y\}\) 对对 \(f _{x-1, y-1}\) 的影响。
容易想到 \(f _{i, j - 1} - f _{i -1 , j -1} = P(s _i)\),同理 \(t _j\)。
\(s _i=t _j \rightarrow P(s _i, t _j) = 2 \times f _{i-1, j-1}\)
\(s _i\neq t _j \rightarrow P(s _i, t _j) = 0\)
$ f _{i, j} = P(s _i) + P(t _j) + P(s _i, t _j)$
所以转移方程
代码实现
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
const int N = 5e3 + 10;
const int mod = 1e9 + 7;
int n,m;
long long f[N][N];
int ans = 0;
int s[N], t[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> s[i];
for (int j = 1; j <= m; j++) cin >> t[j];
f[0][0] = 1;
for (int i = 1; i <= n; i++) f[i][0] = 1;
for (int j = 1; j <= m; j++) f[0][j] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s[i] == t[j]) {
f[i][j] = (f[i - 1][j] + f[i][j - 1]) % mod;
}
else f[i][j] = (f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + mod) % mod;
}
}
cout << f[n][m] << endl;
}
浙公网安备 33010602011771号