求最长上升子序列长度:

单纯的dp时间复杂度是O(n*n)的

dp[i] = max(dp[j]+1); (0=<j<=i-1 && a[i]>a[j]) 

用二分可以减少查找的时间:时间复杂度:O(n*log(n))

模板:

#define maxn 100010
int a[maxn], b[maxn];

// 二分在b[] 数组里找第一个比num 大的数的位置。
int search_(int num, int low, int high) {
    int mid;
    while(low <= high) {
        mid = (low+high)/2;
        if (num >= b[mid]) low = mid + 1;
        else high = mid - 1;
    }
    return low;
}

int LIS(int n) {
    int i, len, pos;
    b[1] = a[1];
    len = 1;
    for (i=2; i<=n; ++i) {
        if (a[i] > b[len]) {// 如果a[i]比b[]中最大的数还大直接插入到最后。   //如果是非递减序列,改为 >= 即可。
            len = len + 1;
            b[len] = a[i];
        }
        else {
            pos = search_(a[i], 1, len);
            b[pos] = a[i];
        }
    }
    return len;
}

 

Eg:题目链接:The All-purpose Zero

题意:给一个序列,序列里的0可以代替任何数,问这个序列里最长递增子序列的长度。0也可以代替负数。(如果不可以的话...)

思路:因为0可以代替任何数,所以ans一定是优先选择0的,然后把每个数减掉它前面的0的个数。为什么减0呢... 比如:1 2 0 3 优先选0,3-1=2,... ,这样就变成了1 2 2 ...求最长上升子序列的长度+0的个数。

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;

#define maxn 100010
int a[maxn], b[maxn];

// 二分在b[] 数组里找第一个比num 大的数的位置。
int search_(int num, int low, int high) {
    int mid;
    while(low <= high) {
        mid = (low+high)/2;
        if (num >= b[mid]) low = mid + 1;
        else high = mid - 1;
    }
    return low;
}

int LIS(int n) {
    int i, len, pos;
    b[1] = a[1];
    len = 1;
    for (i=2; i<=n; ++i) {
        if (a[i] > b[len]) {// 如果a[i]比b[]中最大的数还大直接插入到最后。   //如果是非递减序列,改为 >= 即可。
            len = len + 1;
            b[len] = a[i];
        }
        else {
            pos = search_(a[i], 1, len);
            b[pos] = a[i];
        }
    }
    return len;
}

int main() {
    //freopen("in.cpp", "r", stdin);
    int t;
    scanf("%d", &t);
    int cas = 0;
    while(t--) {
        int n;
        scanf("%d", &n);
        int zeroNum = 0, cnt = 0;
        for (int i=0; i<n; ++i) {
            int temp;
            scanf("%d", &temp);
            if (temp == 0) zeroNum++;
            else {
                temp -= zeroNum;
                a[++cnt] = temp;
            }
        }
        int ans = LIS(cnt) + zeroNum;
        if (cnt == 0) ans -= 1;
        printf("Case #%d: %d\n", ++cas, ans);
    }
    return 0;
}
posted on 2016-07-30 15:22  小小八  阅读(212)  评论(1编辑  收藏  举报