HDU 5791 TWO dp求公共子序列的个数

类似于求最长公共子序列 要稍微变形

dp[i][j]表示前缀子串A[1~i]和B[1~j]的公共子序列的个数

显然应该由dp[i-1][j],dp[i][j-1]转移过来

我们把dp[i][j-1]+dp[i-1][j]分为两部分,一部分为公共部分,另一部分为非公共部分

显然公共部分是 dp[i-1][j-1]

if(A[i]!=B[j]) 我们只要减去公共部分就行 dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]

if(A[i]==b[j]) 我们考虑一下  

对于公共部分 我们可以在后面加上一个A[ i ]让它合理 非公共部分我们显然要计入答案 然后还会多出一个就是A[ i ]这个单独的数

这样说可能不清楚 我们举个例子 

假如A序列是 1 2 4 1

B序列是4 1 3  考虑dp[2][4] 

dp[2][3]的公共序列是:1,4

dp[1][4]的公共序列是:4

两者的公共部分是 4 

非公共部分1显然要计入答案,公共部分4在 A[4]=B[2]时 可以在4后面加上A[4](把41计入答案)所以公共部分也可以计入答案 那么dp[i-1][j]+dp[i][j-1]都可以计入答案  最后+1(A[4]=B[2])

最后dp[2][4]=4,包括(1,4,41,1)

dp[i][j]=dp[i-1][j]+dp[i][j-1]+1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod =  1000000007;
int a[1003],b[1003];
ll dp[1003][1003];
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
	memset(dp,0,sizeof(dp));
	for(int i = 1; i <= n; i++){
		scanf("%d",&a[i]);
	}
	for(int j = 1; j <= m; j++){
		scanf("%d",&b[j]);
	}
	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]+1)%mod;
			}else{
				dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mod)%mod;
			}
		}
	}
	printf("%lld\n",dp[n][m]);
	}
	return 0;
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值