洛谷 P3902 递增

Posted on 2020-05-06 21:09  黑炽  阅读(134)  评论(0编辑  收藏  举报
 1 #include<cstdio>
 2 #include<stdlib.h>
 3 #include<algorithm>
 4 #define INF 10000000000
 5 #define LL long long
 6 using namespace std;
 7 
 8 int a[100001] = { 0 };
 9 LL dp[100001];
10 
11 int main(void) {
12     int n;
13 
14     scanf("%d", &n);
15     for (int i = 0; i < n; i++)
16         scanf("%d", &a[i]);
17 
18     fill(dp, dp + n, INF);
19     /*与memset()函数的区别:
20     两者都可以用来对数组填充,memset是对按照字节来填充的,
21     所以一般用来填充char型数组,也经常用于填充int型的全0或全 - 1操作
22     fill是按照单元来填充的,所以可以填充一个区间的任意值。*/
23     for (int i = 0; i < n; i++)
24         *lower_bound(dp, dp + n, a[i]) = a[i];
25     //上面这步,主要是不断插入a[i]到dp中:在满足找到大于等于dp[]的第一个位置时
26     //因为dp中存的是最长上升子序列的子元素
27     //lower_bound()函数求出来的 dp[n-1]是最长上升序列,所以要减一下。。
28     printf("%d\n", n - (lower_bound(dp, dp + n, INF) - dp));
29     return 0;
30 }

 这个插入的方式我举一个例子,比如4 2 3 1 5

因为所有的元素都是一个很大的值,而lower_bound()函数是找到大于等于参数的第一个位置

那么第一次插入地点在下标为0的地方

  i 0 1 2 3 4
dp[i] 4

 之后,插入2的时候,因为dp[0] 就已经大于2了,所以用2替换掉4

  i 0 1 2 3 4
dp[i] 2

插入3,可知在下标为1时,插入

 i 0 1 2 3 4
dp[i] 2 3

之后插入1,发现在第一个位置,即可替换,

 

 i 0 1 2 3 4
dp[i] 1 3

最后插入5

 

 i 0 1 2 3 4
dp[i] 1 3 5

有点费劲,我举个例子

 

你比如 4是第一个元素,那之后如果碰到比4还要大的数,是不是直接添加到4之后就可以。那如果4 和这个比4大的数 之间有比4小的,那直接相当于添加在4后面,把原本的数覆盖。

比如 4 5 之后如果是2,那么在dp中 4 5 就相当于 2 5 ,其实也就是这个意思:

比如dp中的4 可以被2取代,因为如果碰到 比2大的可以直接加在2后面覆盖掉5,比如4 5 2 3,那就是2 3

,碰到比4大的,也就直接加 那第一个存的就是2了,比如4 5 2 6,那就是2 5 6。 主要是长度就是最长上升序列,跟里面的元素关系不是很大,里面的元素是最长序列元素

 

就可以不断放进去,这样既保留了原来的dp最大长度,又可以内部更新

 

额,,大致是这么个意思,就是不断更新dp,自己也理解的不是很清楚,只是有点想法先记录下。