HDU 5791 Two(LCS求公共子序列个数)

http://acm.split.hdu.edu.cn/showproblem.php?pid=5791

题意:

给出两个序列,求这两个序列的公共子序列的总个数。

 

思路:

和LCS差不多,dp[i][j]表示第一个的前i个和第二个的前j个所包含的公共子序列的个数。

首先考虑a[i]≠b[j]的情况,此时应该容易推得dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]。

那么当a[i]=b[j]时,i和j这两个字符可以单独组成一个公共序列,然后前面dp[i-1][j-1]这些又可以加上这个字符,所以此时dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+dp[i-1][j-1]+1。

总结起来状态转移方程就是:

dp[i][j]=dp[i-1][j]+dp[i][j-1]+1                                a[i]=b[j]
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]                     a[i]≠b[j]

 

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<stack>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 #include<set>
11 using namespace std;
12 typedef long long ll;
13 typedef pair<int,int> pll;
14 const int INF = 0x3f3f3f3f;
15 const int maxn = 1000 + 5;
16 
17 const int mod = 1000000007;
18 
19 int n, m;
20 ll dp[maxn][maxn];
21 int a[maxn],b[maxn];
22 
23 int main()
24 {
25     //freopen("in.txt","r",stdin);
26     while(~scanf("%d%d",&n,&m))
27     {
28         memset(dp,0,sizeof(dp));
29         for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
30         for(int i=1;i<=m;i++)  scanf("%d",&b[i]);
31 
32         for(int i=1;i<=n;i++)
33         {
34             for(int j=1;j<=m;j++)
35             {
36                 if(a[i]==b[j])  dp[i][j]=dp[i-1][j]+dp[i][j-1]+1;
37                 else dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];
38                 dp[i][j]=(dp[i][j]+mod)%mod;
39             }
40         }
41         printf("%lld\n",dp[n][m]);
42     }
43     return 0;
44 }

 

posted @ 2017-10-14 08:55  Kayden_Cheung  阅读(396)  评论(0编辑  收藏  举报
//目录