多校联合训练&hdu5791 Two
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 }