zoukankan      html  css  js  c++  java
  • [BZOJ 2423] [HAOI2010] 最长公共子序列

    2423: [HAOI2010]最长公共子序列

    Time Limit: 10 Sec
    Memory Limit: 128 MB

    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

    【题解】

    参照一般的最长公共子序列的做法

    if s1[i]==s2[j] then f[i][j]=f[i-1][j-1]+1

    else f[i][j]=max(f[i][j-1],f[i-1][j])

    然后我们用g[i][j]来表示方案数。

    对于s1[i]==s2[i]

    g[i][j]=g[i-1][j-1]+k1*g[i-1][j]+k2*g[i][j-1]

    f[i][j]=f[i-1][j] then k1=1 else k1=0;

    f[i][j]=f[i][j-1] then k2=1 else k2=0;

    对于s1[i]!=s2[i]

    g[i][j]=g[i-1][j-1]+k1*g[i-1][j]+k2*g[i][j-1]-k3*g[i-1][j-1]

    f[i][j]=f[i-1][j] then k1=1 else k1=0;

    f[i][j]=f[i][j-1] then k2=1 else k2=0;

    f[i][j]=f[i-1][j-1] then k3=1 else k3=0;

    然后上去发现MLE!!!

    就开了开滚动数组TAT

    然后写跪了QAQ

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include<iostream>
     4 #define max(a,b) a>b?a:b
     5 using namespace std;
     6 const int MOD=100000000;
     7 int f[2][5001],g[2][5001];
     8 char s1[5001],s2[5002];
     9 int len1,len2;
    10 int main() {
    11     scanf("%s%s",s1,s2);
    12     len1=strlen(s1);
    13     len2=strlen(s2);
    14     for (int i=len1-1;i>=1;--i) s1[i]=s1[i-1];
    15     for (int i=len2-1;i>=1;--i) s2[i]=s2[i-1];
    16     len1--;len2--;
    17     int pre=0,now=1;
    18     for (int i=1;i<=len2;i++)  
    19         g[0][i]=1;
    20     g[pre][0]=1;
    21     for (int i=1;i<=len1;++i) {
    22         for (int j=1;j<=len2;++j) f[now][j]=g[now][j]=0;
    23         g[now][0]=1;
    24         for (int j=1;j<=len2;++j)
    25             if(s1[i]==s2[j]) {
    26                 f[now][j]=f[pre][j-1]+1;
    27                 g[now][j]=g[pre][j-1],g[now][j]%=MOD;
    28                 if (f[now][j]==f[pre][j]) g[now][j]+=g[pre][j],g[now][j]%=MOD;
    29                 if (f[now][j]==f[now][j-1]) g[now][j]+=g[now][j-1],g[now][j]%=MOD;
    30             }
    31             else {
    32                 f[now][j]=max(f[pre][j],f[now][j-1]);
    33                 if (f[now][j]==f[pre][j]) g[now][j]+=g[pre][j],g[now][j]%=MOD;
    34                 if (f[now][j]==f[now][j-1]) g[now][j]+=g[now][j-1],g[now][j]%=MOD;
    35                 if (f[now][j]==f[pre][j-1]) g[now][j]-=g[pre][j-1],g[now][j]=(g[now][j]+MOD)%MOD;
    36             }//cout<<i<<" "<<j<<" "<<f[now][j]<<" "<<g[now][j]<<endl;}
    37         int t=pre;pre=now;now=t;
    38     }
    39     printf("%d
    %d
    ",f[pre][len2],g[pre][len2]);
    40     return 0;
    41 }
    View Code
  • 相关阅读:
    2020年9月29日
    随机生成验证码
    动手动脑java语法基础
    Java语法之动手实验
    代码大全2 读书笔记
    java动手动动脑之字串联接
    二柱子问题
    生成随机四则运算1
    可变参数
    2020年9月30日
  • 原文地址:https://www.cnblogs.com/TonyNeal/p/bzoj2423.html
Copyright © 2011-2022 走看看