zoukankan      html  css  js  c++  java
  • Codeforces

    DP的学习计划,刷 https://codeforces.com/problemset?order=BY_RATING_ASC&tags=dp

    遇到了这道题 https://codeforces.com/problemset/problem/702/A

    以为是最长上升子序列(Longest Increasomg Subsequence)的模板题,发现自己不会做

    记录一下大概的思路:

    (O(n^2)) 的算法:

    • (L[i]) 选择 (A[i]) 为结尾的LIS的长度
    • (P[i]) 选择 (A[i]) 为结尾的LIS的倒数第二个元素的Position(可以用来复现整个LIS)
    • 临时变量 (k) ,表示 (A[i]) 计算时找到的前面最长的LIS的位置
    • 对于每个 (A[i]) ,遍历它前面的每个 (A[j]) ,记录所有满足 (A[j]<A[i]) (可以把 (A[i]) 接在后面)且 (L[j]>L[k]) (更长的子序列)
    • (L[i]=L[k]+1)
    • (P[i]=k)

    (O(nlogn)) 的算法:

    • (L[i]) 长度为(i+1) 的IS的末位元素的最小值
    • (length) 前 (i) 个元素构成的LIS的长度
    • 升序遍历 (i),故 (length) 非降,而且构造的过程中 (L) 数组是递增的
    • 如果 (L[length-1]<A[i]) ( (A[i]) 可以接在当前最长的(长度为 (length) 的)LIS后面),则 (L[length++]=A[i])
    • 否则在已确定的 (L[0]~L[length]) 中(长度为 (1) 到 (length) 闭区间的LIS的最末元素)二分找到能更新的位置并更新 $*lower\_bound(L,L+length,A[i])=A[i]$
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    
    int A[100005];
    int L[100005];
    
    int lis(){
        L[0]=A[0];
        int length=1;
        for(int i=1;i<n;i++){
            if(L[length-1]<A[i]){
                L[length++]=A[i];
            }
            else{
                *lower_bound(L,L+length,A[i])=A[i];
                //1 7 2 5,已有序列1 7,lower_bound(2)得到7,可以把长度为2的LIS的末尾换成2
            }
        }
        return length;
    }
    
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%d",&A[i]);
        }
        printf("%d
    ",lis());
    
    }

    复原的时候也很简单,把$L[0]~L[length-1]$全部输出就可以了

    但是最后我发现这个702A并不是LIS,因为他不是子序列而是子串!

    2019-01-16

  • 相关阅读:
    Linux 实战
    bash 环境配置及脚本
    Linux vi/vim
    Linux 正则表达式
    001 KNN分类 最邻近算法
    测序名解
    流式细胞术
    CircRNA 环化RNA
    笔记总结
    Flume
  • 原文地址:https://www.cnblogs.com/Yinku/p/10278063.html
Copyright © 2011-2022 走看看