Cod sursa(job #603701)

Utilizator razyelxrazyelx razyelx Data 18 iulie 2011 13:33:56
Problema Subsir crescator maximal Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.83 kb
#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;
}