zoukankan      html  css  js  c++  java
  • #dp#C 公共子序列

    题目

    给定两个字符串(s1,s2),求它们的(LCS)
    满足(|s1|leq 10^6,|s2|leq 10^3)


    分析

    考场写了(O(|s1|*|s2|))成功TLE,
    考虑突破口为(|s2|)不够大,考虑转为判定,
    (dp[i][j])表示原来存在最小的(k)使得(f[k][i]geq j),不存在为(n+1)
    那么(dp[i][j]=min{dp[i-1][j],nxt[dp[i-1][j-1]][s2[i]]})
    然后二分(dp[m][ans])即可,(nxt)数组要预处理,其实就是子序列自动机
    转为判定是真的妙


    代码

    #include <cstdio>
    #include <cstring>
    #define rr register
    using namespace std;
    const int N = 1011, M = 1000011;
    char s1[M], s2[N];
    int dp[N][N], nxt[M][26], ls[26], n, m;
    inline signed min(int a, int b) { return a < b ? a : b; }
    signed main() {
        freopen("lcs.in", "r", stdin);
        freopen("lcs.out", "w", stdout);
        scanf("%s%s", s1 + 1, s2 + 1), memset(dp, 42, sizeof(dp));
        n = strlen(s1 + 1), m = strlen(s2 + 1);
        memset(ls, 42, sizeof(ls));
        for (rr int i = 0; i <= m; ++i) dp[i][0] = 0;
        for (rr int i = n; i >= 0; --i) {
            for (rr int j = 0; j < 26; ++j) nxt[i][j] = ls[j];
            if (i > 0)
                ls[s1[i] - 97] = i;
        }
        for (rr int i = 1; i <= m; ++i)
            for (rr int j = 1; j <= i; ++j) {
                dp[i][j] = dp[i - 1][j];
                if (dp[i - 1][j - 1] <= n)
                    dp[i][j] = min(dp[i][j], nxt[dp[i - 1][j - 1]][s2[i] - 97]);
            }
        rr int l = 0, r = m;
        while (l < r) {
            rr int mid = (l + r + 1) >> 1;
            if (dp[m][mid] <= n)
                l = mid;
            else
                r = mid - 1;
        }
        return !printf("%d", l);
    }
    
  • 相关阅读:
    随机生成4位验证码(包含数字, 字母)
    eval注册和登录
    51单片机中断机制(定时器/计数器)
    CS106B
    机器学习算法之旅(转载)
    Ubuntu系统使用记录
    2. 自然语言处理预备知识
    1. 自然语言处理描述
    前端学习网站
    2016年总结,2017年计划
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14067826.html
Copyright © 2011-2022 走看看