线性DP模板

最长上升子序列

定义

  • 设有由\(n\)个不相同的整数组成的数列,记为: \(b_1,b_2...b_n\)\(b_i!=b_j(i!=j)\)
    若存在\(i_1<i_2<...<i_n\)且有\(b_{i_1}<b_{i_2}...<b_{i_3}\)则称为长度为\(e\)的不下降序列。

\(O(n^2)\)的做法

int lis(int a[], int n) {
    int f[N], ans = 0;
    for(int i = 1; i <= n; i++) f[i] = 1;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j < i; j++)
            if (a[j] < a[i] && f[i] < f[j] + 1)
                f[i] = f[j] + 1;
        ans = max(ans, f[i]);
    }
    return ans;
}

\(O(n log n)\)的做法

  • 对于\(n^2\)的写法,状态是无法优化的,第二维是求\(j~i\)符合条件的最大子序列和。
    \(b(i)\)定义为长度为\(i\)的最长上升子序列的最后一位数最小是多少。

  • 看定义可能不太懂,因为我就没看懂
    看着挺复杂,其实也没啥,看代码注释吧。

int lis(int a[], int n) {
    int f[N], cnt = 1;
    f[cnt] = a[1];
    for(int i = 2; i <= n; i++) {
        if (a[i] > f[cnt]) f[++cnt] = a[i];
        //求上升序列,如果a[i]比最后一位大,就在后面再添一个
        else f[lower_bound(f+1, f+cnt+1, a[i])-f] = a[i];
        //找到比他小的替换掉他
        //upper_bound() 用到库<algorithm>
        //也可以手写二分
    }
    return cnt;
}

最长公共子串

定义

  • 一列字符C既是A的子串,又是B的子串,就称C为A和B的公共子串。
    (这里子串指的是连续的)

\(O(n^2)\)

    scanf("%s %s", a+1, b+1);
    n = strlen(a+1); m = strlen(b+1);
    for(int i = 1; i <= n; i++)
        for(int j = m; j > 0; j--) {
            if (a[i] == b[j])
                s[j] = s[j-1] + 1, ans = max(ans, s[j]);
            else s[j] = 0;
        }

最长公共子序列

定义

  • 一列字符C既是A的子序列,又是B的子序列,就称C为A和B的公共子序列。
    (这里子序列可以不连续)

\(O(n^2)\)

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if (a[i] == b[j]) f[i][j] = f[i-1][j-1] + 1;
            else f[i][j] = max(f[i-1][j], f[i][j-1]);
    //f[n][n]为最后的结果

\(O(nlogn)\)

  • 没有重复数字的直接用离散化处理,有重复的用vector记录,放进b数组的时候按从后往前的顺序排列。

无重复

    scanf("%d", &n);
    tot = 0;
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]), m[a[i]] = ++tot;
    for(int i = 1; i <= n; i++)
        scanf("%d", &b[i]), b[i] = m[b[i]];
    tot = 0;
    s[++tot] = b[1];
    for(int i = 2; i <= n; i++) {
        if (s[tot] < b[i]) s[++tot] = b[i];
        else s[lower_bound(s+1, s+tot+1, b[i])-s] = b[i];
    }
    printf("%d\n", tot);

有重复

    scanf("%d", &n);
    for (int i = 1, x; i <= n; i++)
        scanf("%d", &x), m[x].push_back(i);
    for (int i = 1, x; i <= n; i++) {
        scanf("%d", &x);
        for (int j = m[x].size()-1; j >= 0; j--)
            a[++len] = m[x][j];
    }
    f[cnt=1] = a[1];
    for (int i = 2; i <= len; i++)
        if (a[i] > f[cnt]) f[++cnt] = a[i];
        else f[lower_bound(f+1, f+cnt+1, a[i])-f] = a[i];
    printf("%d\n", cnt);
posted @ 2020-06-22 20:34  Shawk  阅读(119)  评论(0编辑  收藏  举报