题目:
题意:
给定一些导弹的高度。
一个导弹系统只能拦截高度不增的一系列导弹,问如果只有一个系统最多能拦截多少导弹。
再问,如果要拦截所有导弹最少需要多少系统。
思路:
对于第一个问题其实就是找整个序列中的最长不升子序列。
对于第二个问题就是找整个序列中的最长上升子序列。因为当有一个高度大于前面的高度时一个系统就搞定不了了。
最长上升子序列用动态规划是可以做的,但是这题会卡。
$O(N^2)$的动规做法是,$dp[i] = max(dp[i], dp[j] + 1),if height[i] > height[j]$
还有一种$O(NlogN)$的做法。这时我们维护一个单调栈。数是从小到大排序的,对于新的一个数,如果比栈顶的元素大,就直接加入栈中。
如果新的数比栈顶要小,我们就在栈中二分查找一个最小的大于新的数的数替换掉。
因为对于已经选好了的序列,我们替换前面的数的话并不会影响答案的长度。但是用更小的数替换大的数将有更大的机会让加入的数变多。
而二分找这样的数也非常简单,使用STL里的upper_bound()和lower_bound()就可以解决了。
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。
lower_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。
upper_bound( begin,end,num,greater<type>() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。
1 #include2 #include 3 #include