Cod sursa(job #781788)

Utilizator lauraxxxLaura Balan lauraxxx Data 25 august 2012 00:46:44
Problema Subsir crescator maximal Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 3.29 kb
//O(N * logN) cu arbori de intervale

#include <stdio.h>
#include <algorithm>
#define NMAX 100100
#define MOD 9901

using namespace std;

int x[NMAX], sortedX[NMAX];

struct query
{
	int num, val;
	query ()
	{
		num = 0; val = 0;
	}
} arb[4 * NMAX + 69]; //Acest numar ma excita serios

query arbQuery(int st, int dr, int nod, int wantedLeft, int wantedRight)
{
	query ans, now;
	
	if (wantedLeft > wantedRight)
		return ans;
	
	//Verific ca intervalul curent [st, dr] sa fie inclus in [wantedLeft, wantedRight]
	//caz in care nu mai are rost sa merg mai departe, ma opresc si trimit toata solutia
	if (wantedLeft <= st && dr <= wantedRight)
		return arb[nod];
	//Daca am intervale care se intersecteaza cu wantedLeft, wantedRight, o parte din solutia optima ar putea fi acolo
	int med = (st + dr) / 2;
	if (wantedLeft <= med)
	{
		now = arbQuery(st, med, 2 * nod, wantedLeft, wantedRight);
		if (now.val == ans.val)
		{
			ans.num += now.val;
			ans.num = ans.num % MOD;
		}
		if (now.val > ans.val)
			ans.num = now.num, ans.val = now.val;
	}
	if (med < wantedRight)
	{
		now = arbQuery(med + 1, dr, 2 * nod + 1, wantedLeft, wantedRight);
		if (now.val == ans.val)
		{
			ans.num += now.val;
			ans.num = ans.num % MOD;
		}
		if (now.val > ans.val)
			ans = now;
	}
	
	return ans;
}

void arbUpdate(int st, int dr, int nod, int wantedNod, query info)
{
	if (st == dr) //Am ajuns la nodul cautat din arbore
	{
		arb[nod] = info;
		return ;
	}
	int med = (st + dr) / 2;
	
	int choice;
	if (wantedNod <= med)
	{
		arbUpdate(st, med, 2 * nod, wantedNod, info);
		choice = 2 * nod;
	}
	else
	{
		arbUpdate(med + 1, dr, 2 * nod + 1, wantedNod, info);
		choice = 2 * nod + 1;
	}
	
	if (info.val == arb[nod].val)
	{
		arb[nod].num += info.num;
		arb[nod].num %= MOD;
	}
	if (info.val > arb[nod].val)
		arb[nod] = info;
}

int main()
{
	int i, N;
	
	freopen("subsiruri.in", "r", stdin);
	freopen("subsiruri.out", "w", stdout);
	
	//Citesc vectorul
	scanf("%d", &N);
	for (i = 1; i <= N; i ++)
		scanf("%d", &x[i]);
	
	//Normalizez datele
	for (i = 1; i <= N; i ++)
		sortedX[i] = x[i];
	sort(sortedX + 1, sortedX + N + 1);
	
	int st, dr, med;
	for (i = 1; i <= N; i ++)
	{
		st = 1; dr = N; 
		while (st <= dr)
		{
			med = (st + dr) / 2;
			if (sortedX[med] == x[i])
			{
				x[i] = med;
				break;
			}
			if (sortedX[med] < x[i])
				st = med + 1;
			else
				dr = med - 1;
		}
	}
	
	query now;
	
	for (i = 1; i <= N; i ++)
	{
		//Un QUERY pe intervalul [i, j] imi da lungimea unei subsir crescator maximal si cate exista
		//astfel incat ultimul element din subsir sa se afle in intervalul [i, j]
		
		//La pasul curent un subsir crescator maximal care se termina in x[i] poate fi obtinut din 
		//orice alt subsir crescator maximal care se termina undeva in intervalul [1, x[i] - 1]
		now = arbQuery(1, N, 1, 1, x[i] - 1);
		now.val ++;
		if (now.num == 0)
			now.num = 1;
		//Lungimea subsirului crescator maximal va creste cu 1 (am adaugat elementul x[i]), iar numarul va
		//ramane acelasi (cel dat de queryul dinainte, deoarece se adauga un singur element la ce era inainte)
		arbUpdate(1, N, 1, x[i], now);
	}
	
	//Afisez solutia finala
	now = arbQuery(1, N, 1, 1, N);
	printf("%d\n%d", now.val, now.num);
	return 0;
}