/*
給出兩個串A,B <=2000,構造一個新串,使得該新串的子序列是A,B,且長度最短
求新串的方案數
顯然是最小長度n+m-lcs
比賽時,我錯誤做法是對相鄰匹配點中間的字符進行排列,如
abcd
aefd
就固定a,d,中間的b,c,e,f排列,當然需要b在c前,e在f前
但這種做法遇到多個匹配點時就有問題了,如
be
babo
上面的b可以跟下面兩個匹配,直接像上面那樣子排列會有重復的問題
當時局限在上面的思路,沒搞出 .
其實不難,直接dp即可
dp[i,j]表示以A[i]或者B[j]結尾的串的個數
如果A[i] = B[j],則dp[i,j] = dp[i-1,j-1] 因為這時必須匹配A[i],B[j]
否則,lcs[i-1,j] > lcs[i,j-1] 則dp[i,j] = dp[i-1,j] 這時新串肯定是A[i]結尾,因為取的是dp[i-1,j]
lcs[i-1,j] < lcs[i,j-1] 則dp[i,j] = dp[i,j-1] 這時新串肯定是B[i-1]結尾
lcs[i-1,j] = lcs[i,j-1] 則dp[i,j] = dp[i-1,j] +dp[i,j-1] 這時新串可以是A[i]或B[j]結尾,但不會重復,因為尾部不同
坑得,當時比賽時,沒想打如果取dp[i-1,j],自然是以A[i]結尾的!!!
結尾不同,不會導致重復計數的!!
用組合數學的方法算時,不清楚尾部是什么
*/
#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;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|