• BZOJ 2423 最长公共子序列


    Description

    字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij = yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。

    Input

    第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。
    第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。

    Output

    第1行输出上述两个最长公共子序列的长度。
    第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。
     

    Sample Input

    ABCBDAB.
    BACBBD.

    Sample Output

    4
    7

    HINT

    首先,求最长子序列就是一个经典的dp了。f[i][j]表示s1到第i位,s2到第j位的最长子序列,f[i][j]=max(f[i-1][j-1]+(s1[i]==s2[j]),f[i-1][j],f[i][j-1])。

    麻烦的就是方案的转移,我们另g[i][j]表示s1到第i位,s2到第j位的最长子序列的方案数。考虑以下的几种情况:

    1.s1[i]==s2[j],f[i][j]=f[i-1][j-1]+1。g[i][j]=g[i-1][j-1]+(f[i-1][j]==f[i][j])*g[i-1][j]+(f[i][j-1]==f[i][j])*g[i][j-1],三种情况互不包含(g[i-1][j-1]指s1[i]与s2[j]配对;若f[i-1][j]==f[i][j]的话,一定有s1[i-1]与s2[j]配对(否则f不会相等),累加g[i-1][j];同理g[i][j-1]指的是s1[i]与s2[j-1]配对),直接加即可。

    2.否则的话,f[i][j]=max(f[i-1][j],f[i][j-1]),若两者相等,则g[i][j]=g[i-1][j]+g[i][j-1]-g[i-1][j-1],因为中间部分两者都计算了一遍,否则就加上大者即可。

    由于O(n^2)的空间肯定是开不下的,所以我们要利用滚动数组。

     1 #include<cstring>
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 using namespace std;
     6 
     7 #define rhl (100000000)
     8 #define maxn 5010
     9 char s1[maxn],s2[maxn];
    10 int f[2][maxn],g[2][maxn],n,m;
    11 
    12 inline void dp()
    13 {
    14     n = strlen(s1+1),m = strlen(s2+1);
    15     s1[n--] = s2[m--] = 0;
    16     for (int i = 0;i <= m;++i) g[0][i] = 1;
    17     for (int i = 1;i <= n;++i)
    18     {
    19         int p = i&1,q = p^1;
    20         g[p][0] = 1;
    21         for (int j = 1;j <= m;++j)
    22         {
    23             g[p][j] = 0;
    24             if (s1[i] == s2[j])
    25             {
    26                 f[p][j] = f[q][j-1]+1;
    27                 g[p][j] += g[q][j-1];
    28                 if (f[q][j] == f[p][j]) g[p][j] += g[q][j];
    29                 if (f[p][j-1] == f[p][j]) g[p][j] += g[p][j-1];
    30             }
    31             else
    32             {
    33                 f[p][j] = max(f[p][j-1],f[q][j]);
    34                 if (f[p][j-1] > f[q][j]) g[p][j] = g[p][j-1];
    35                 else if (f[q][j] > f[p][j-1]) g[p][j] = g[q][j];
    36                 else
    37                 {
    38                     g[p][j] = g[q][j]+g[p][j-1];
    39                     if (f[q][j-1] == f[p][j]) g[p][j] -= g[q][j-1];
    40                 }
    41             }
    42             while (g[p][j] >= rhl) g[p][j] -= rhl;
    43             while (g[p][j] < 0) g[p][j] += rhl;
    44         }
    45     }
    46     printf("%d
    %d",f[n&1][m],g[n&1][m]);
    47 }
    48 
    49 int main()
    50 {
    51     freopen("2423.in","r",stdin);
    52     freopen("2423.out","w",stdout);
    53     scanf("%s%s",s1+1,s2+1);
    54     dp();
    55     fclose(stdin); fclose(stdout);
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    linux 安装软件三种方法
    megalo -- 网易考拉小程序解决方案
    层叠上下文 Stacking Context
    关于document.write
    学习块格式化上下文(BlockFormattingContext)
    jQuery 源码分析 8: 回头看jQuery的构造器(jQuery.fn,jQury.prototype,jQuery.fn.init.prototype的分析)
    简化版的Flappy Bird开发过程(不使用第三方框架)
    jQuery 源码分析 7: sizzle
    jQuery 源码分析6: jQuery 基本静态方法(二)
    jQuery 源码分析5: jQuery 基本静态方法(一)
  • 原文地址:https://www.cnblogs.com/mmlz/p/4281307.html
Copyright © 2020-2023  润新知