Cod sursa(job #1254736)

Utilizator smallOneAdina Mateescu smallOne Data 3 noiembrie 2014 12:53:59
Problema Subsir crescator maximal Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.66 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);
}

pair<long long, int> vp[LIM];
pair<int, long long> rez[LIM];
long long x;

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

    int n, a[LIM];

    cin >> n;

    // ================ citire si normalizare ===============
    for(int i = 1; i <= n; i++) {
        cin >> x;
        vp[i - 1] = make_pair(x, i);
    }
    sort(vp, vp + n);
    int t = 1;
    a[vp[0].second] = t;
    rez[a[vp[0].second]] = make_pair(t, vp[0].first);
    for(int i = 1; i < n; i++) {
        if(vp[i].first != vp[i - 1].first) {
            t++;
        }
        a[vp[i].second] = t;
        rez[a[vp[i].second]] = make_pair(t, vp[i].first);
    }

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

    // ================ rezolvarea cerintei conform comentariilor de la inceputul programului ================
    inceput = 1;
    sfarsit = n;
    // dp[i] = "lungimea celui mai lung subsir care se termina in i"
    for(int i = 1; i <= n; i++) {
        maxim = -1;
        sfarsit = a[i] - 1;
        if(sfarsit > 0) {
            queryARB(1, 1, n);
            dp[i] = max(dp[i], maxim + 1);
        }
        pos = a[i];
        val = dp[i];
        sfarsit = n;
        updateARB(1, 1, n);
    }

    // problema cere lg celui mai lung subsir (nu neaparat cel care se termina in n) -> caut maximul dintre toate cele n calculate
    int mx = -1, pos = -1;
    for(int i = 1; i <= n; i++) {
        if(mx < dp[i]) {
            mx = dp[i];
            pos = i;
        }
    }

    // ================== afisarea rezultatelor ===============
    cout << mx << "\n";

    vector<long long> v;
    for(int i = pos; i > 0 && mx > 0; i--) {
        if(dp[i] == mx) {
            v.push_back(rez[a[i]].second);
            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;
}