hdu5282 最长公共子序列的变形

http://acm.hdu.edu.cn/showproblem.php?pid=5282

Problem Description
Xuejiejie loves strings most. In order to win the favor of her, a young man has two strings  X Y  to Xuejiejie. Xuejiejie has never seen such beautiful strings! These days, she is very happy. But Xuejiejie is missish so much, in order to cover up her happiness, she asks the young man a question. In face of Xuejiejie, the young man is flustered. So he asks you for help.

The question is that :
Define the  L  as the length of the longest common subsequence of  X  and  Y .( The subsequence does not need to be continuous
in the string, and a string of length  L  has  2L  subsequences containing the empty string ). Now Xuejiejie comes up with all subsequences of length  L  of string  X , she wants to know the number of subsequences which is also the subsequence of string  Y .
 

Input
In the first line there is an integer  T , indicates the number of test cases.

In each case:

The first line contains string  X , a non-empty string consists of lowercase English letters.

The second line contains string  Y , a non-empty string consists of lowercase English letters.

1|X|,|Y|1000 |X|  means the length of  X .
 

Output
For each test case, output one integer which means the number of subsequences of length  L  of  X  which also is the subsequence of string  Y  modulo  109+7 .
 

Sample Input
  
  
2 a b aa ab
 

Sample Output
  
  
1 2
/**
hdu5282 最长公共子序列的变形
题目大意:给定两个字符串,求二者的最长公共子序列,在a中出现过的,有多少是b的子序列
解题思路:来自官方题解。
          首先我们用O(n2)的动态规划算法处理出dp数组,dp[i][j]表示X串的前i个字符和Y
          串的前j个字符的最长公共子序列的长度,在这个基础上我们再进行一个动态规划。
          用f[i][j]表示在X串的前i个字符中,有多少个长度为dp[i][j]的子序列在Y的前j个
          字符中也出现了。转移:若dp[i−1][j]==dp[i][j],则f[i][j]+=f[i−1][j],表示i
          这个字符不选;再考虑选i这个字符,找到Y串前j个字符中最靠后的与X[i]匹配的字
          符的位置,设为p,若dp[i−1][p−1]+1==dp[i][j],则f[i][j]+=f[i−1][p−1]。最终
          的答案即为f[n][m]。复杂度O(n2)。

*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const int maxn=1005;
int dp[maxn][maxn],n,m,wei[maxn][maxn];
char a[maxn],b[maxn];
LL f[maxn][maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s%s",a,b);
        n=strlen(a);
        m=strlen(b);
        memset(dp,0,sizeof(dp));
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1]);
                if(a[i]==b[j])
                    dp[i+1][j+1]=max(dp[i][j]+1,dp[i+1][j+1]);
            }
        }
        memset(wei,0,sizeof(wei));
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<26;j++)
            {
                wei[i][j]=wei[i-1][j];
            }
            wei[i][b[i-1]-'a']=i;
        }
        memset(f,0,sizeof(f));
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                if(dp[i][j]==0)
                {
                    f[i][j]=1;
                    continue;
                }
                if(dp[i-1][j]==dp[i][j])
                {
                    f[i][j]=(f[i][j]+f[i-1][j])%mod;
                }
                int p=wei[j][a[i-1]-'a'];
                if(p)
                {
                    if(dp[i-1][p-1]+1==dp[i][j])
                    {
                        f[i][j]=(f[i][j]+f[i-1][p-1])%mod;
                    }
                }
            }
        }
        printf("%I64d\n",f[n][m]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值