AcWing 895 最长上升子序列 - (线性DP) or (贪心+二分优化)
Posted Chivas_/Regal
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 895 最长上升子序列 - (线性DP) or (贪心+二分优化)相关的知识,希望对你有一定的参考价值。
LIS问题
题目:
思路1 - 线性dp
数据量1000,可以用
n
2
n^2
n2的复杂度去解
在上升子序列中,考虑每一位都必须比前面那一位要大
我们设置
d
p
[
i
]
dp[i]
dp[i]表示从第1位到第i位的最长上升子序列
所以我们在枚举每一位(设为
a
[
i
]
a[i]
a[i])的时候
都利用前面的dp最优解去查一下
如果有一位(设为
a
[
j
]
a[j]
a[j])的值小于
a
[
i
]
a[i]
a[i]
那么我们完全可以把
a
[
i
]
a[i]
a[i]放到
a
[
j
]
a[j]
a[j]后面,得到的这一种子序列
d
p
[
i
]
=
d
p
[
j
]
+
1
dp[i]=dp[j]+1
dp[i]=dp[j]+1
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
代码:
const int N = 1005;
int a[N];
int dp[N];
int res;
int main(){
int n; read(n);
for(int i = 1, x; i <= n; i ++) read(a[i]);
for(int i = 1; i <= n; i ++){ dp[i] = 1;//初始化为1,因为自己本身一个数就是一个LIS
for(int j = 1; j < i; j ++) if(a[j] < a[i]) dp[i] = MAX(dp[j] + 1, dp[i]);//如果前面的某一位小于当前的这一位,完全可以把这一位接到前面那一位后面
res = MAX(res, dp[i]);//维护一下最大答案
}write(res);
return 0;
}
思路2 - 贪心+二分优化
我们贪心地去想
每一位能否加入我们的答案 其实取决于我们当前答案子序列里面的最后一位是不是比我们枚举到的这一位要小
所以我们要尽可能让最后一位变小
同时最后一位能否正确的变小 其实取决于我们前面的数是不是足够小
因为我们要保证我们的答案是一个上升的
在上升序列中我们枚举到位置
i
i
i时可以使用二分来看我们要替换哪一位让它尽可能变小 或者没有比它大的话就加入到我们的答案中
在此过程中顺序是会被打乱的
但是我们要知道的是:
我们是否改变答案长度,是根据我们是否加数来定的,而是否加数,是根据最后一位来定的,当我们加进去一个新数的时候,其实在那时也满足了一个LIS
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
代码:
int a[1000005];
vector<int> vec;
int main(){
int n; read(n);
for(int i = 1, x; i <= n; i ++) read(a[i]);
for(int i = 1, x; i <= n; i ++){
if(vec.empty() || vec.back() < a[i]) vec.push_back(a[i]);//这个是最大的就塞到队尾
else vec[lower_bound(vec.begin(), vec.end(), a[i]) - vec.begin()] = a[i];//能变小的话替换一下
//其实顺序被打乱了,但是在求解size的时候并不影响,因为我们打乱完一遍也就是一个新的子序列,打乱一半是无影响的
}write(vec.size());
return 0;
}
以上是关于AcWing 895 最长上升子序列 - (线性DP) or (贪心+二分优化)的主要内容,如果未能解决你的问题,请参考以下文章