发现只要不是写在博客上的算法都容易忘==
意义可以望文生义==
做法
正常我们找一个a[j]小于等于a[i]的最长的d[a[j]] ( d为dp数组 )需要遍历整个数组,整体复杂度为n^2 现在我们需要做得就是在尽量快的时间内找到这个a[j];
于是我们新定义d[i]的意义为长度为i的上升序列的最小结尾是多少,每次加入一个数的时候,二分查找大于等于a[i]的最小的d[j]的值;然后把d[j]改为a[i];如果当前a[i]大于d[len] (len为当前最长序列长度)。那么就把len+1, 然后把新的d[len]设为a[i];
当需要找的序列变为最长不下降子序列时,只需要把判断尾数时的“大于”改为“大于等于”即可;
代码
#include<cstdio>
#include<iostream>
#define maxn 10010
using namespace std;
int a[maxn], d[maxn];
int len;
int b_search(int k) {
int L = 0, R = len;
while(L < R) {
int M = L + (R-L)/2;
if(d[M] >= k) R = M;
else L = M+1;
}
return L;
}
int main() {
int n, m;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
len = 1;
d[1] = a[1];
for(int i = 1; i <= n; i++) {
if(a[i] > d[len])
d[++len] = a[i];
else {
int p = b_search(a[i]);
d[p] = a[i];
}
}
cout << len;
}