Codeforces - 702A - Maximum Increase - 简单dp

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\n",lis());

}

 

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

 

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

2019-01-16

posted @ 2019-02-24 21:37  韵意  阅读(191)  评论(0编辑  收藏  举报