HDU 5773 The All-purpose Zero 求LIS

weixin_30588675發表於2020-04-05

求最長上升子序列長度:

單純的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;
}

轉載於:https://www.cnblogs.com/icode-girl/p/5721023.html

相關文章