【题解】
这题就是要求最长不下降子序列。
不同的是,它不是要求你求出来最长不下降子序列的各个值具体是什么。
它要求的是以ai结尾的最长不下降子序列的长度f[i].
但是这题的坑点在于。它不让你用那么方便的n^2算法。要用nlogn算法才行。所以就去找咯。
原来的f[i]要改一下意思了。变成长度为i的最长上升(严格上升)序列的最后一个元素的最小值是啥。
一开始len = 1;f[1] = a1;
然后for i = 2->n
if (a[i] > f[len]) //这个很好理解吧?就是如果大于长度为len的最后一个元素.则最长XX的长度递增。
{
len++;
f[len] = a[i]; //然后把新的元素接上去就好
直接输出len.表示以a[i]结尾的最长不下降子序列的长度为len;
}
else
{
找到一个k
f[k-1]<a[i]<=f[k];
因为a[i] <= f[k]且f[k-1]<a[i] 则说明其可以代替f[k]成为一个更小的f[k]'。
那么就让f[k] = a[i]就好;
这个k可以用二分查找找到(鬼才想去写这个二分查找。跟屎一样难写!)
所以我们用STL解决(就是algorithm这个头文件里的东西。)
它叫。我看下我能不能默下来lower__count??
我看下。
哦,错了
是lower_bound(f+1,f+1+len,a[i])-f;
你没看错最后面减去了一个数组
然后前面就是类似sort(a+1,a+1+len);
表示从1..len找到这样的k;
然后f[k] = a[i];
然后输出k.表示以a[i]为结尾的最长不下降子序列的长度为k;
}
【代码】
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; int t, n, a[100001], f[100001], last = 1, ans[100001]; int main() { scanf("%d", &t); for (int mm = 1; mm <= t; mm++) { scanf("%d", &n); for (int i = 1; i <= n; i++)//读入数据 scanf("%d", &a[i]); f[1] = a[1];//最长不下降子序列长度为1的最小结尾元素一开始就是a[1] ans[1] = 1;//没用的。。别管 printf("1");//表示以a1为结尾的最长不下降子序列的长度为1 last = 1; for (int i = 2; i <= n; i++) { if (f[last] < a[i])//因为更新了最长不下降子序列的长度 { last++; printf(" %d", last);//所以以其结尾的元素的长度为last; f[last] = a[i]; } else { int pos = lower_bound(f + 1, f + 1 + last, a[i]) - f;//找到合适的K值 f[pos] = a[i];//放在这个位置 printf(" %d", pos);//输出它的长度、即以a[i]为结尾的最长不下降子序列的长度。 } } printf(" "); } return 0; }