【NOIP】导弹拦截

【NOIP】导弹拦截

题目

题目描述

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

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

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

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

输入输出样例

输入 #1 复制
389 207 155 300 299 170 158 65
输出 #1 复制
6
2

说明/提示

为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分

每点两问,按问给分

分析

这是道 “最长上升子序列 一类的问题” 题目分为两个问题。

1.后面每一发炮弹都不能高于前一发的高度,所以是求 最长不上升子序列

2.求最少要几套炮弹,是求** 最长上升子序列** (这是一个什么定理来着,最长上升子序列有多长,就是
最少需要几套,可以自己拿样例模拟下,很好懂)

做法:
这里用到 slt 里的 lower_bound与upper_bound (本质是运用二分,也可以自己写个二分搜索代替)

lower_bound:找出序列中第一个 >= x的数
upper_bound: 找出序列中第一个 > x的数

并且要求序列 是 有序的,上升的序列。(这是默认用法,当然也可以改变,)
用法和sort()差不多,详细自己百度吧。。(等有时间我也总结下,怕忘了。)

代码

代码先是 常写的 o(n^2)写法, 后是 o(nlogn)写法。

#include<iostream>
#include<cstdio>
using namespace std;


int a[100005];    
int n;
int dp[100005];
int dp2[100005];
int ans1,ans2;
int main(){
	
	while(scanf("%d",&a[++n] )!= EOF);
	n--;
	
	for(int i=1;i<=n;i++){
		dp[i] = 1;
		for(int j=1;j<i;j++){
			if(a[i] <=a[j]){
				dp[i] = max(dp[i],dp[j]+1);
			}
		}
		ans1 = max(ans1,dp[i]);
	}
	
	for(int i=1;i<=n;i++){
		dp2[i] = 1;
		for(int j=1;j<i;j++){
			if(a[i] > a[j]){
				dp2[i] = max(dp2[i],dp2[j]+1);
			}
		}
		ans2 = max(ans2,dp2[i]);
	}
	cout<<ans1<<endl<<ans2;
	return 0;
}
//本来有注释的,但是好像写完没保存,懒的再写了

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n;
int a[100005];
int b[100005],c[100005];
int main(){
	while(scanf("%d",&a[++n])!=EOF){
	}
	n--;	
	int len1=1,len2=1;
	b[1]=a[1];
	c[1]=a[1];
	for(int i=2;i<=n;i++){
		if(b[len1]>=a[i]) b[++len1]=a[i];
		else{
			int k=upper_bound(b+1,b+1+len1,a[i],greater<int>())-b;
			b[k]=a[i];
		}
		if(c[len2]<a[i]) c[++len2]=a[i];
		else{
			int k=lower_bound(c+1,c+1+len2,a[i])-c;
			c[k]=a[i];
		}
	}
	cout<<len1<<endl<<len2;
	return 0;
} 
发布了75 篇原创文章 · 获赞 1 · 访问量 3627

猜你喜欢

转载自blog.csdn.net/A793488316/article/details/105316472