// Subsir crescator maximal - complexitate O(NlogN), solutie cu arbori de intervale
#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
using namespace std;
int n, a[100010], A, B, val, X, Y, position, sol, pozsol;
bool ok;
int best[100010], pred[100010];
vector <int> vsol;
struct arbore
{
int minim, maxim, best, pos;
};
arbore aint[262150];
inline void Read()
{
ifstream f("scmax.in");
f>>n;
int i;
for(i=1; i<=n; i++)
f>>a[i];
f.close();
}
inline void Build(int nod, int st, int dr)
{
if (st == dr)
{
aint[nod].minim = aint[nod].maxim = a[st];
aint[nod].best = 1;
aint[nod].pos = -1; // pos = pozitia in vectorul a in care se afla best
return ;
}
int mij, fiu;
mij = (st+dr)>>1;
fiu = nod<<1;
Build(fiu, st, mij);
Build(fiu+1, mij+1, dr);
aint[nod].minim = min(aint[fiu].minim, aint[fiu+1].minim);
aint[nod].maxim = max(aint[fiu].maxim, aint[fiu+1].maxim);
aint[nod].best = max(aint[fiu].best, aint[fiu+1].best);
if (aint[fiu].best > aint[fiu+1].best)
aint[nod].pos = aint[fiu].pos;
else
aint[nod].pos = aint[fiu+1].pos;
}
inline void Query(int nod, int st, int dr)
{
if (A <= st && dr <= B && aint[nod].maxim < val)
{
if (aint[nod].best > X)
{
X = aint[nod].best;
Y = aint[nod].pos;
ok = true;
}
return ;
}
int mij, fiu;
mij = (st+dr)>>1;
fiu = nod<<1;
if (A <= mij && aint[fiu].minim < val)
{
Query (fiu, st, mij);
}
if (mij < B && aint[fiu+1].minim < val)
{
Query (fiu+1, mij+1, dr);
}
}
inline void Update(int nod, int st, int dr)
{
if (st == dr)
{
aint[nod].best = val;
aint[nod].pos = st; // = position
return ;
}
int mij, fiu;
mij = (st+dr)>>1;
fiu = nod<<1;
if (position <= mij)
{
Update(fiu, st, mij);
}
else
{
Update(fiu+1, mij+1, dr);
}
if (aint[fiu].best > aint[fiu+1].best)
{
aint[nod].best = aint[fiu].best;
aint[nod].pos = aint[fiu].pos;
}
else
{
aint[nod].best = aint[fiu+1].best;
aint[nod].pos = aint[fiu+1].pos;
}
}
inline void Solve()
{
Build(1, 1, n);
int i;
for(i=1; i<=n; i++)
{
val = a[i];
A = 1;
B = i-1;
X = Y = 0;
ok = false;
Query(1, 1, n);
// returneaza in X maximul dintre best[1 ... i-1] cu proprietatea ca a[j] < a[i]
// si in Y pozitia in vectorul a la care se afla acest best;
if (ok == false)
Y = -1;
best[i] = X + 1;
pred[i] = Y;
if (best[i] > sol)
{
sol = best[i];
pozsol = i;
}
position = i;
val = X + 1;
Update(1, 1, n);
}
}
inline void Write()
{
ofstream g("scmax.out");
g<<sol<<"\n";
do
{
vsol.push_back(a[pozsol]);
pozsol = pred[pozsol];
} while (pozsol != -1);
vector <int>::iterator it;
for (it = vsol.end()-1; it >= vsol.begin(); it--)
g<<*it<<" ";
g<<"\n";
g.close();
}
int main()
{
Read();
Solve();
Write();
return 0;
}