Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.
Input
The input contains multiple test cases.
For each test case, the first line cantains two integers N,M(1≤N,M≤1000). The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
For each test case, the first line cantains two integers N,M(1≤N,M≤1000). The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
Output
For each test case, output the answer mod 1000000007.
Sample Input
3 21 2 32 13 21 2 31 2
这道题目很像求最长子序列的问题(用DP数组解决),但是这道题是要求两个AB数列当中数列A和数列B的非空子数列有多少对是相同的.
确定DP方程:
DP[i][j]表示A串前i个字符和B串前j个字符之间由多少相同的子序列两种思路:
1.用123 12来说明
两个数组元素 | (从1开始) | 1 | 2 | 3 | |
0 | 0 | 0 | 0 | ||
1 | 0 | 1 | 1 | 1 | |
2 | 0 | 1 | 3 | 3 |
e[i+1][j+1]=(e[i+1][j]+e[i][j+1]-e[i][j]+N)%N;//去重就是上图中红蓝L型线相交的元素(用了两遍),此时是I=2,J=2;
if(a[i]==b[j])
e[i+1][j+1]=(e[i+1][j+1]+e[i][j]+1)%N; //如果当前字符相等,那么前面的dp[i][j]就能和这个新的相等字符匹配一遍,所以需要加上dp[i-1][j-1]+1;
全部代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N=1e9+7;
int e[1005][1005];
int main(){
int n,m;
int a[1005],b[1006];
while(cin>>n>>m){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(e,0,sizeof(e));
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<m;i++)
scanf("%d",&b[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
e[i+1][j+1]=(e[i+1][j]+e[i][j+1]-e[i][j])%N;
if(a[i]==b[j])
e[i+1][j+1]=(e[i+1][j+1]+e[i][j]+1)%N;
}
cout<<e[n][m]<<endl;
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// cout<<e[i][j]<<" ";
// cout<<endl;
// }
}
}
2.另一种思路找出状态转移方程
dp[i][j]表示的是序列A前i个数字和序列B前j个数字的公共子序列的总个数,那么的dp公式就可以这么表示
(表示不好推)
理解一下此公式若最尾部的a[i]和b[j]相等的话,那么单独的a[i]和b[j]组成1个相同子序列。
同时我们可以想一下之前的前i-1个子序列和前j-i个子序列再加上a[i]又能组成dp[i-1]个公共子序列。
当然了,包含第i个数字的前i个序列a和前j-1个数字的序列b以及包含第j个数字的前j个序列b和前i-1个数字的序列a也要算上。
所以把上面3种情况一合并就是前i-1个子序列a和前j个子序列b的公共子序列个数加上前i个子序列a和前j-1个子序列b的公共子序列个数再加1。
这里包含了2倍的dp[i-1][j-1]个数。
如果a[i]和b[j]不相等的话,减去一个dp[i-1][j-1]个数即可。
本题中另一个注意点就是dp[i][j]可能为负,此时的处理方法是加上一个MOD
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N=1e9+7;
int e[1005][1005];
int main(){
int n,m;
int a[1005],b[1006];
while(cin>>n>>m){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(e,0,sizeof(e));
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<m;i++)
scanf("%d",&b[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
e[i+1][j+1]=(e[i+1][j]+e[i][j+1]-e[i][j]+N)%N;
if(a[i]==b[j])
e[i+1][j+1]=(e[i+1][j+1]+1)%N;
else
e[i+1][j+1]=(e[i+1][j]+e[i][j+1]-e[i][j]+N)%N;
}
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=m;j++)
// cout<<e[i][j]<<" ";
// cout<<endl;
// }
}
}