Cod sursa(job #1254592)

Utilizator smallOneAdina Mateescu smallOne Data 2 noiembrie 2014 23:07:55
Problema Subsir crescator maximal Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 2.97 kb
#include <cstdio>
#include <iostream>
#include <fstream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctype.h>
#include <cstring>
#include <string>
#include <ctime>
#include <cassert>
#include <utility>

using namespace std;

#define LIM 100005

int dp[LIM], A[4 * LIM + 10], maxim, pos, val, inceput, sfarsit;

// idee ce utilizeaza DP + Arb de Intervale

// ideea acestui program este ca se calculeaza cu
// programare dinamica: lungimea celui mai lung subsir care se termina in i si care respecta ca e strict crescator
// doar ca acum se priveste inapoi si atunci tranzitiile sunt:
// dp[i] = max(dp[j] | j < i && dp[i] > dp[j]) + 1;
// pentru a calcula acel maxim in timp mai mic de o(n) putem sa o facem utilizand arborii de intervale

void updateARB(int nod, int st, int dr) {
    if(st == dr) { // am ajuns la o frunza - am ajuns pe pozitia care vreau sa updatez
        A[nod] = val;
        return;
    }
    int m = (st + dr) / 2;
    if(pos <= m)
        updateARB(2 * nod, st, m);
    else
        updateARB(2 * nod + 1, m + 1, dr);

    A[nod] = max(A[2 * nod], A[2 * nod + 1]);
}

void queryARB(int nod, int st, int dr) {
    if(inceput <= st && dr <= sfarsit) {
        if(maxim < A[nod])
            maxim = A[nod];
        return;
    }
    int m = (st + dr) / 2;
    if(m >= inceput)
        queryARB(2 * nod, st, m);
    if(m < sfarsit)
        queryARB(2 * nod + 1, m + 1, dr);
}

int main() {
	freopen("scmax.in", "r", stdin);
	freopen("scmax.out","w", stdout);

    int n, a[LIM];

    cin >> n;

    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }

    // initializare dp
    for(int i = 0; i <= n; i++) {
        dp[i] = 1;
    }

    inceput = 1;
    sfarsit = n;
    // problema cere lg celui mai lung subsir (nu neaparat cel care se termina in n) -> caut maximul dintre toate cele n calculate
    int mTotal = -1;
    // dp[i] = "lungimea celui mai lung subsir care se termina in i"
    for(int i = 1; i <= n; i++) {
        maxim = -1;
        for(int j = 1; j < i; j++) {
            if(a[j] < a[i]) {
                pos = j;
                val = dp[j];
                updateARB(1, 1, n);
            }
        }
        queryARB(1, 1, n);
        dp[i] = maxim + 1;
    }

    int mx = -1, pos = -1;
    for(int i = 1; i <= n; i++) {
        if(mx < dp[i]) {
            mx = dp[i];
            pos = i;
        }
    }
    cout << mx << "\n";

    vector<int> v;
    for(int i = pos; i > 0 && mx > 0; i--) {
        if(dp[i] == mx) {
            v.push_back(a[i]);
            mx--;
        }
    }

    reverse(v.begin(), v.end());
    int sz = v.size();
    for(int i = 0; i < sz - 1; i++) {
        cout << v[i] << " ";
    }
    if(sz - 1 >= 0)
        cout << v[sz - 1] << "\n";
	return 0;
}