题解 | #拦截导弹#
拦截导弹
https://www.nowcoder.com/practice/218f3db1f66d465bbf9578625aa90785
等价于求两个问题:
问题1: 求最长不增(小于等于)子序列的长度
方面就是 线性dp
问题2: 求 最少可以划分出不增(小于等于)子序列的个数
#include <iostream>
#include <set>
using namespace std;
const int N = 1010;
int h[N];
int dp[N]; //dp[i]表示 长度为i的 子数组的 最长不增(小于等于)子序列的长度。
int main() {
int n;
cin >> n;
for(int i = 1;i<=n;i++){
cin >> h[i];
dp[i] = 1; //给dp赋 初值
}
int res1 = 1;
//找给定 高度数组中的最长下降子序列
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<i;j++){
if(h[i]<=h[j]){
dp[i] = max(dp[i],dp[j]+1);
}
}
if(dp[i]>res1)
res1 = dp[i];
}
cout << res1 << endl;
// 在高度数组中, 看可以 划分出最少多少个 下降子序列,子序列的个数最少,说明一个下降子序列尽可能长 ?
/*算法:
1. 从前往后扫描, 当前高度<序列上一个高度,就加入序列,直到末尾
2. 到达末尾后,进行下一遍扫描,流程和步骤1 一样
3. */
set<int> st;
int last; //序列上一个值
int res2 = 0;
while(st.size()!=n){
int isFirst = 1; //一个for形成一个 序列,当是某序列中第一个 数字时,不在需要它<=last了
for(int i = 1;i<=n;i++){
if(isFirst && st.count(i)==0){
st.insert(i);
last = h[i];
isFirst = 0;
}
else if(st.count(i)==0 && h[i]<=last){
st.insert(i);
last = h[i];
isFirst = 0;
}
}
res2 += 1;
}
cout << res2 << endl;
return 0;
}
// 64 位输出请用 printf("%lld")
查看7道真题和解析

