描述:
给定两个序列a1, a2, ..., an和b1, b2, ..., bm,求公共子序列的对数。
子序列是指从序列中删除任意多个元素后剩下元素按照先后顺序构成的子序列。
两个子序列相同是指所有元素值依次相同。
输入:
第一行为n和m(1≤n, m≤2000)。
第二行为a1, a2, ..., an。
第三行为b1, b2, ..., bm。
1≤ai≤1e5
输出:
输出答案 mod 1e9+7
题意:给定两个序列,求公共子序列的对数。(值相同但位置不同的子序列算作新的一对)
大致思路:使用dp求解,让dp[i][j]表示a数组的前i个数和b数组的前j个数中公共子序列的对数,然后列状态转移方程;
当a[i]!=b[j]时,dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1]。因为此时公共子序列的对数没有增加,dp[i][j]仍然是之前的相同子序列的对数。而dp[i - 1][j]表示的是 跟b[j]相关的公共子序列的对数+a数组的前i-1个数和b数组的前j-1个数中公共子序列的对数,dp[i][j-1]表示的是 跟a[i]相关的公共子序列的对数+a数组的前i-1个数和b数组的前j-1个数中公共子序列的对数。所以要把dp[i-1][j-1]减掉来去重。
当a[i] == b[j]时,dp[i][j]要在前面的基础上加上dp[i - 1][j - 1] + 1。因为同时跟a[i]和b[j]相关公共子序列的对数增加了,分别是自己本身的一对和前面不用上a[i],b[j]的dp[i-1][j-1]对。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void IOS()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
const ll mod = 1e9 + 7;
int n, m;
int a[2007], b[2007];
ll dp[2007][2007];
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int j = 1; j <= m; j++) cin >> b[j];
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mod) % mod;
if (a[i] == b[j])dp[i][j] = (dp[i][j] + dp[i - 1][j - 1] + 1) % mod;
}
}
cout << (dp[n][m] + 1) % mod;//最后加上空序列
}
signed main()
{
IOS();
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
/*
4 4
1 2 3 4
1 3 2 4
12
2 2
1 1
1 1
6
*/