多校联合训练&hdu5791 Two

hdu5791

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

代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define MOD 1000000007
 5 #define LL long long
 6 using namespace std;
 7 LL dp[1005][1005];
 8 LL a[1005];
 9 LL b[1005];
10 int main()
11 {
12     int n,m;
13     while(~scanf("%d%d",&n,&m))
14     {
15         memset(dp,0,sizeof(dp));
16         for(int i = 1;i<=n;i++)
17             scanf("%d",&a[i]);
18         for(int j = 1;j<=m;j++)
19             scanf("%d",&b[j]);
20         for(int i = 1;i<=n;i++)
21         {
22             for(int j = 1;j<=m;j++)
23             {
24                 if(a[i]==b[j])
25                     dp[i][j]+=dp[i-1][j]+dp[i][j-1]+1;
26                 else
27                     dp[i][j]+=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1];//极有可能出现负数
28                 if(dp[i][j]<0)
29                     dp[i][j]+=MOD;
30                 dp[i][j]=dp[i][j]%MOD;
31             }
32         }
33         printf("%I64d\n",dp[n][m]);
34     }
35     return 0;
36 }

 

posted @ 2016-08-11 15:15  fancy_boy  阅读(383)  评论(0编辑  收藏  举报