51nod 1153 選擇子序列 (好題)

這裏寫圖片描述

這個題很不錯。
採用貪心的思想:首先考慮到在整個序列中取最大值一定是最優的,也就是說B數組的第一個數是A數組的中最大值的下標。而且通過題意我們發現,一旦選定了某個數就把當前的區間劃分成兩份。比如說第一次選了9,第二次選了10, 那麼下一次肯定不會選8(這幾個數字說的都是下標),不會垮區間選數,那麼我們就可以每次選一個區間最大值,再把區間劃分成兩份分別查找最大值就可以了。因爲每個元素最多訪問一遍,再加上線段樹找最大值,就是nlong的複雜度了

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long ll;
const int maxn = 1e5;
int n;
struct p{
    ll id, val;
}a[maxn * 2];

void build(int root, int l, int r){
    if(l == r){
        scanf("%lld", &a[root].val);
        a[root].id = l;
        return;
    }
    int mid = (l + r) >> 1;
    build(root << 1, l, mid);
    build(root << 1|1, mid + 1, r);
    if(a[root << 1].val > a[root << 1|1].val){
        a[root].val = a[root << 1].val;
        a[root].id = a[root << 1].id;
    }else {
        a[root].val = a[root << 1|1].val;
        a[root].id = a[root << 1|1].id;
    }
}

struct p qu(int root, int l, int r, int s, int t){
    p x, y;
    x.val = y.val = -1e10;
    if(s <= l && t >= r){
        return a[root];
    }
    int mid = (l + r) >> 1;
    if(s <= mid) x = qu(root << 1, l, mid, s, t);
    if(t > mid) y = qu(root << 1|1, mid + 1, r, s, t);
    if(x.val > y.val) return x;
    return y;
}

int dfs(int l, int r){
    p t;
    if(l == r) return 1;
    if(l > r) return 0;
    t = qu(1, 1, n, l, r);
    return max(dfs(l, t.id - 1), dfs(t.id + 1, r)) + 1;
}

int main(){
    scanf("%d", &n);
    build(1, 1, n);
    printf("%d\n", dfs(1, n));
    return 0;
}

2017/7/31 更新:
因爲這個題目在大佬收錄的“o(n)可以過的好題”裏面,我就重寫了一下,用單調棧代替了線段樹。效率提高了一些吧

#include<cstdio>
#include<algorithm>
#include<stack>
using namespace std;

typedef long long ll;
const int maxn = 1e5;
int a[maxn];
int left[maxn], right[maxn];
int n;
stack<int> s;

int dfs(int t){
    if(t == 0) return 0;
    if(left[t] == 0 && right[t] == 0) return 1;
    return max(dfs(left[t]), dfs(right[t])) + 1;
}

int main(){
    int t, pos;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        pos = a[i] > t ? i : pos;
        t = i == 1 ? a[i] : max(a[i], t);
        while(!s.empty() && a[s.top()] < a[i]){
            left[i] = s.top();
            s.pop();
        }
        s.push(i);
    }
    for(int i = n; i >= 1; i--){
        while(!s.empty() && a[s.top()] < a[i]){
            right[i] = s.top();
            s.pop();
        }
        s.push(i);
    }
    printf("%d\n", dfs(pos));
    return 0;
}
發佈了65 篇原創文章 · 獲贊 3 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章