思路
题目要求我们求最长公共子序列,那么这就是一个 线性dp
了。
我们不妨确定一个设数,如 d p i , j dp_{i,j} dpi,j 表示在序列 a a a 中前 i i i 个数,与数列 b b b 中前 j j j 个数所组成的最长序列的长度。那就有以下 2 2 2 种情况。
- 若 a i = b i a_i=b_i ai=bi,那么: d p i , j = d p i − 1 , j + d p i , j − 1 dp_{i,j}=dp_{i-1,j}+dp_{i,j-1} dpi,j=dpi−1,j+dpi,j−1
- 若 a i ≠ b i a_i\ne b_i ai=bi,那么: d p i , j = d p i − 1 , j + d p i , j − 1 − d p i − 1 , j − 1 dp_{i,j}=dp_{i-1,j}+dp_{i,j-1}-dp_{i-1,j-1} dpi,j=dpi−1,j+dpi,j−1−dpi−1,j−1
你可能要问:为什么要减去 d p i − 1 , j − 1 dp_{i-1,j-1} dpi−1,j−1 呢?
回答:根据容斥原理,多的部分是要减掉的
代码如下
#include<iostream>
using namespace std;
int a[10010],b[10010],dp[10010][10010];
const int mod=1000000007;
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>b[i];
dp[0][0]=1;
for(int i=1;i<=n;i++)dp[i][0]=1;
for(int j=1;j<=m;j++)dp[0][j]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i]==b[j]){
dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
}
else{
dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
}
}
}
cout<<(dp[n][m]%mod+mod)%mod;
return 0;
}