Cod sursa(job #603701)
#include <fstream>
using namespace std;
const int N = 100001;
int uniq[N], norm[N], sir[N], L[N], p[N], AIB[N], stack[N],n;
/**
uniq contine sirul initial sortat si fara dubluri pentru a putea
determina vectorul norm, care este vectorul initial normalizat
L[i] stocheaza lungimea sirului care se termina in i.
AIB[i] stocheaza indicele j astfel L[j] este lungimea maxima formata pana la acest i.
facem acest lucru deoarece interogarea ne da toate elementele mai mici decat numarul_curent
toate aceste elemente care pot fi acesate din cel numarul_curent vor stoca acelasi indice care
are lungimea maxima din intervalul 1, numarul_curent
astfel daca avem valoarea curenta norm[i] vom cauta in 1 .. norm[i-1] si ne vom opri la un j, 1 <= j < i
posibil chiar primul care ne da indicele elementului in care se termina sirul maximal de pana acum.
de exemplu. daca numarul curent este 4 atunci cautam intre 1 si 3. presupunem ca ca avem 1 2 4 3.
cum 3 este dupa 4 el nu poate di o continuare al acestuia. dar in norm[3] va fi valoarea 2 (norm[3] = 2)
deoarece primul mai mic ca 4 si maximal este norm[2]. il putem salva in norm[3] (chiar daca norm de 3 nu a fost atins)
pentru a ajunge la valoare mai repede. in cazul lui i = 3 (norm[3]) tot se parcurge si pt i=1 si i =2 dar daca i =4
s-ar determina maximul pana de la 1 .. 4 pentru ca umratoare mutare face indicele i = 0. deci chiar daca i-4 nu este maxim
si maximul este i=2 acest lucru este aflat mai repede si nu este necesara parcurgerea pana la i=2.
acest avantaj se resimte pt numere mari.
**/
void update(int x, int i){
for ( ; x <= n; x += (x ^ ( x - 1 ) ) & x )
if ( L[i] > L[ AIB[ x ] ])
AIB [ x ] = i;
}
int query(int x){
int maxim = 0;
for ( ; x; x -= ( x ^ ( x - 1 ) ) & x)
if ( L[maxim] < L[ AIB[ x ] ])
maxim = AIB[x];
return maxim;
}
int main(){
ifstream fin ("scmax.in");
ofstream fout ("scmax.out");
int best = 0;
int k = 1;
fin >> n;
for (int i = 1; i<= n; i++){
fin >> sir[i];
uniq[i] = norm[i] = sir[i];
}
sort( uniq, uniq+n+1);
k = 1;
for (int i = 2; i<=n; i++)
if (uniq[i] != uniq[k])
uniq[++k] = uniq[i];
for (int i = 1; i<=n; i++)
norm[i] = lower_bound(uniq, uniq+n+1, norm[i]) - uniq;
// norm este nromalizat
for (int i = 1; i<= n; i++) {
int x = query(norm[i] - 1); // indicele elementului mai mic decat norm[i] si cu lungime maxima.
p[i] = x; // p[i] stocheaza indicele valorii precendete(adica valoarea mai mica decat norm[i] si cu L[i] maxim);
L[i] = L[x] + 1;
update(norm[i], i);
if ( L[best] < L[i] ) best = i;
}
fout << L[best] << "\n";
k = 0;
for (int i = best; i; i = p[i])
stack[ ++k ] = sir[i];
while ( k ) fout << stack[ k--] << " ";
fout << "\n";
return 0;
}