/*
給出兩個(gè)串A,B <=2000,構(gòu)造一個(gè)新串,使得該新串的子序列是A,B,且長(zhǎng)度最短
求新串的方案數(shù)
顯然是最小長(zhǎng)度n+m-lcs
比賽時(shí),我錯(cuò)誤做法是對(duì)相鄰匹配點(diǎn)中間的字符進(jìn)行排列,如
abcd
aefd
就固定a,d,中間的b,c,e,f排列,當(dāng)然需要b在c前,e在f前
但這種做法遇到多個(gè)匹配點(diǎn)時(shí)就有問題了,如
be
babo
上面的b可以跟下面兩個(gè)匹配,直接像上面那樣子排列會(huì)有重復(fù)的問題
當(dāng)時(shí)局限在上面的思路,沒搞出 .
其實(shí)不難,直接dp即可
dp[i,j]表示以A[i]或者B[j]結(jié)尾的串的個(gè)數(shù)
如果A[i] = B[j],則dp[i,j] = dp[i-1,j-1] 因?yàn)檫@時(shí)必須匹配A[i],B[j]
否則,lcs[i-1,j] > lcs[i,j-1] 則dp[i,j] = dp[i-1,j] 這時(shí)新串肯定是A[i]結(jié)尾,因?yàn)槿〉氖莇p[i-1,j]
lcs[i-1,j] < lcs[i,j-1] 則dp[i,j] = dp[i,j-1] 這時(shí)新串肯定是B[i-1]結(jié)尾
lcs[i-1,j] = lcs[i,j-1] 則dp[i,j] = dp[i-1,j] +dp[i,j-1] 這時(shí)新串可以是A[i]或B[j]結(jié)尾,但不會(huì)重復(fù),因?yàn)槲膊坎煌?br />
坑得,當(dāng)時(shí)比賽時(shí),沒想打如果取dp[i-1,j],自然是以A[i]結(jié)尾的!!!
結(jié)尾不同,不會(huì)導(dǎo)致重復(fù)計(jì)數(shù)的!!
用組合數(shù)學(xué)的方法算時(shí),不清楚尾部是什么
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#include<set>
#include<cstring>
#include<string>
#include<stack>
#include<cassert>
#include<sstream>
#include<list>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 2010;
const int MOD = 1000000007;
int dp[MAXN][MAXN], lcs[MAXN][MAXN];
char A[MAXN], B[MAXN];
int main()
{
//freopen("in","r", stdin);
//freopen("out","w", stdout);
while (~scanf("%s%s", A+1, B+1)) {
int n = strlen(A+1);
int m = strlen(B+1);
memset(dp, 0, sizeof dp);
memset(lcs, 0, sizeof lcs);
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
for (int i = 0; i <= m; i++) {
dp[0][i] = 1;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m;j ++) {
if (A[i] == B[j]) {
lcs[i][j] = lcs[i-1][j-1]+1;
dp[i][j] = dp[i-1][j-1];
} else if (lcs[i-1][j] > lcs[i][j-1]) {
lcs[i][j] = lcs[i-1][j];
dp[i][j] = dp[i-1][j];
} else if (lcs[i-1][j] < lcs[i][j-1]) {
lcs[i][j] = lcs[i][j-1];
dp[i][j] = dp[i][j-1];
} else {
lcs[i][j] = lcs[i-1][j];
dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % MOD;
}
}
//cout<<lcs[n][m]<<endl;
cout<<dp[n][m]<<endl;
}
return 0;
}
|