题解:导弹拦截(洛谷P1020)

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是≤50000 \le 50000≤50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式
1行,若干个整数(个数≤100000 \le 100000≤100000)

输出格式
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入输出样例
输入 #1
389 207 155 300 299 170 158 65

输出 #1
6
2

解析

第一问相当于最长不上升子序列
第二问相当于维护一个末尾尽可能大的不下降子序列
(写的时候竟然可以把第一问复制到第二问,符号全反过来再填个等于就AC了。。。《离谱》)
关于等号具体解释见代码注释

代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int tot=1;
int x[100005];
int main(){
	while(scanf("%d",&x[tot])!=EOF){
		mx=max(mx,x[tot]);
		tot++;
	}
	tot--;
	int q[100005]={ },num1=0;
	for(int i=1;i<=tot;i++){
		if(q[num1]>=x[i]||num1==0){
			q[++num1]=x[i];
			continue;
		}
		int ans;
		for(ans=1;ans<=num1;ans++){
			if(q[ans]<x[i]) break;/*
		这里没有等号,使结尾的min尽可能的大
		后面的元素才能尽可能的可以放到队尾从而使队列最长*/ 
		}
		q[ans]=x[i];
	}
	int num=0;
	for(int i=1;i<=tot;i++){
		if(q[num]<x[i]){
			q[++num]=x[i];
			continue;
		}
		int st=1,ed=num,mid,ans=ed;
		for(ans=1;ans<=num;ans++){
			if(q[ans]>=x[i]) break;/*
		这里与上一问相比多个等号,使结尾的max尽可能的大
		后面才能尽可能的不需要增加一组*/ 
		}
		q[ans]=x[i];
	}
	printf("%d\n%d",num1,num);
}
上一篇:(一)插入排序


下一篇:CGBTN2108复习汇总