nlogn的最长上升子序列,但是要输出LIS的长度和一个最小字典序的LIS。
然后怎么输出这个最小字典序的LIS就成了问题,然后就翻被人的题解,发现就只有还保存那个F[]数组就行
F数组还是存储的到这个数的LIS的长度,然后假如F[i]==F[j],则必有a[i]>=a[j],所以就肯定选择a[j]是对的
然后就倒着扫一遍,相同的F[i]就取i靠后的那个。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 100005
int a[maxn], D[maxn], F[maxn], path[maxn];
int n, len;
int main()
{
//freopen("input.txt", "r", stdin);
int T, x;
scanf("%d", &T);
while (T--)
{
len = 1;
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d", &a[i]);
D[0] = -1;
F[0] = 1;
D[1] = a[0];
for (int i = 1; i < n; ++i)
{
x = lower_bound(D + 1, D + len + 1, a[i]) - D;
D[x] = a[i];
//printf("%d %d %d\n", i, x, len);
if (x == len + 1)
++len;
F[i] = x;
}
for (int i = n - 1, t = len; i >= 0; --i)
{
if (t == 0)
break;
if (F[i] == t)
path[t--] = a[i];
}
printf("%d\n", len);
for (int i = 1; i <= len; ++i)
{
if (i == len)
printf("%d\n", path[i]);
else
printf("%d ", path[i]);
}
}
//system("pause");
//while (1);
return 0;
}