zoukankan      html  css  js  c++  java
  • 洛谷 P2516 [HAOI2010]最长公共子序列

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

    其实就是让你求一个最长公共子序列的长度和方案数

    因为长度最大是5000,所以考虑dp

    (f_{i,j})表示第一个字符串a的前1...i的子串和第二个字符串b的前1...j的子串的最长公共子序列长度

    那么有两种情况

    [f_{i,j}=egin{cases}f_{i-1,j-1}&; (a_i=b_j) \ max(f_{i-1,j},f_{i,j-1})&; (a_i e b_j)end{cases} ]

    然后就可以(O(n^2))转移了

    至于方案数也使用一样统计,开一个(dp_{i,j})表示第一个字符串a的前1...i的子串和第二个字符串b的前1...j的子串的最长公共子序列的方案数

    我们只需要统计(f_{i-1,j})(f_{i,j-1})中与(f_{i,j})相等的把方案数相加,然后又有两种情况

    [dp_{i,j}+=egin{cases}dp_{i-1,j-1}&\, (a_i=b_j & f_{i,j}=f_{i-1,j-1}+1) \ -dp_{i-1,j-1}&\, (a_i e b_j & f_{i,j}=f_{i-1,j-1})end{cases} ]

    负数的情况就是减去算重的一次

    初始化就是(dp_{i,0}=dp_{0,j}=1quad(0le ile len_a,0le jle len_b))

    然后这题还卡空间(真是毒瘤

    但是这个转移方程滚动还是很显然的,第一维只留两个状态就可以了,然后算答案和统计方案数也可以放在一起做

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 5000;
    const int p = 1e8;
    using namespace std;
    int n,la,lb,dp[3][N + 5],f[3][N + 5];
    char a[N + 5],b[N + 5];
    int main()
    {
        scanf("%s",a + 1);
        scanf("%s",b + 1);
        la = strlen(a + 1);
        lb = strlen(b + 1);
        la--;
        lb--;
        for (int i = 0;i <= lb;i++)
            dp[0][i] = 1;
        dp[1][0] = 1;    
        for (int i = 1;i <= la;i++)
            for (int j = 1;j <= lb;j++)
            {
                dp[i % 2][j] = 0;
                if (a[i] == b[j])
                {
                    f[i % 2][j] = f[(i - 1) % 2][j - 1] + 1;
                    dp[i % 2][j] += dp[(i - 1) % 2][j - 1]; 
                }
                else
                    f[i % 2][j] = max(f[i % 2][j - 1],f[(i - 1) % 2][j]);
                if (f[(i - 1) % 2][j] == f[i % 2][j])
                    dp[i % 2][j] += dp[(i - 1) % 2][j];
                if (f[i % 2][j - 1] == f[i % 2][j])
                    dp[i % 2][j] += dp[i % 2][j - 1];
                if (f[i % 2][j] == f[(i - 1) % 2][j - 1] && a[i] != b[j])
                    dp[i % 2][j] -= dp[(i - 1) % 2][j - 1];                
                dp[i % 2][j] = (dp[i % 2][j] + p) % p;            
            }
        printf("%d
    %d",f[la % 2][lb],dp[la % 2][lb]);
        return 0;
    }
    
  • 相关阅读:
    Windows 窗体设计器中的设计时错误
    union all 里面的order by
    docx转doc时,防止公式被转成图片的解决办法
    学习方向推荐
    关于验收测试的几个困惑
    《实例化需求》读书笔记
    VS2010中使用 SpecFlow + Selenium.WebDriver
    敏捷团队成员应具备的素质
    Jolt Awards: The Best Books
    在Ajax.ActionLink的OnBegin,onComplete等事件中使用this【解决办法】
  • 原文地址:https://www.cnblogs.com/sdlang/p/13068287.html
Copyright © 2011-2022 走看看