1010. 拦截导弹
题目链接
1010. 拦截导弹
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。
由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
共一行,输入导弹依次飞来的高度。
输出格式
第一行包含一个整数,表示最多能拦截的导弹数。
第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。
数据范围
雷达给出的高度数据是不大于 \(30000\) 的正整数,导弹数不超过 \(1000\)。
输入样例:
389 207 155 300 299 170 158 65
输出样例:
6
2
解题思路
LIS,贪心
关键在于求至少有多少个非上升的子序列覆盖所有序列,可采用一种贪心策略:从前往后遍历每个导弹高度,如果当前导弹高度大于之前所有选定非上升子序列的最后一个高度,则应该重新设定一个子序列,否则将该导弹插入前面不高于最后一个导弹高度且最小的那个子序列中
证明:对于一个导弹来说其总会在某个子序列中,假设最优解不在贪心解的某个子序列的位置上,而无论当前导弹在哪个子序列中该子序列最后一个高度都是固定的,而相比于最优解来说贪心解都可以换成最优解而不影响序列个数,而且直觉上来说贪心解比最优解更优
此解法正好对应LIS问题的贪心解法,即求至少有多少个非上升的子序列覆盖所有序列等价于求最长上升子序列长度
- 时间复杂度:\(O(n^2)\)
代码
// Problem: 拦截导弹
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1012/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1005;
int f[N],g[N],n,a[N];
int main()
{
n=1;
while(cin>>a[n])n++;
n--;
for(int i=1;i<=n;i++)f[i]=g[i]=1;
for(int i=1;i<=n;i++)
for(int j=1;ja[j])g[i]=max(g[i],g[j]+1);
cout<<*max_element(f+1,f+1+n)<<'\n'<<*max_element(g+1,g+1+n);
return 0;
}