P1020 [NOIP1999 普及组] 导弹拦截

[NOIP1999 普及组] 导弹拦截

题目描述

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

输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式

一行,若干个整数,中间由空格隔开。

输出格式

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

样例 #1

样例输入 #1

389 207 155 300 299 170 158 65

样例输出 #1

6
2

提示

对于前 50% 数据(NOIP 原题数据),满足导弹的个数不超过 104 个。该部分数据总分共 100 分。可使用O(n2) 做法通过。
对于后 50% 的数据,满足导弹的个数不超过 105 个。该部分数据总分也为 100 分。请使用 O(nlogn) 做法通过。

对于全部数据,满足导弹的高度为正整数,且不超过 5×104

此外本题开启 spj,每点两问,按问给分。


upd 2022.8.24:新增加一组 Hack 数据。

第一问:最长不上升子序列
第二问:最长上升子序列
优化:树状数组/vector/线段树/二分O(nlogn)

点击查看代码
//树状数组维持最大值
int ask(int x)
{
	int ans=0;
	for(;x;x-=x&-x)ans=max(ans,c[x]);
	return ans;
}

void add(int x,int y)
{
	for(;x<=maxx;x+=x&-x)c[x]=max(c[x],y);
}

int main()
{
	while(scanf("%d",&a[++n])!=EOF);
	for(int i=1;i<n;i++)maxx=max(maxx,a[i]);
	int f=1,g=1;
	for(int i=n-1;i>=1;i--)
	{
		int x=ask(a[i])+1;
		add(a[i],x);
		f=max(f,x);
	}
	memset(c,0,sizeof c);
	for(int i=1;i<n;i++)
	{
		int x=ask(a[i]-1)+1;
		add(a[i],x);
		g=max(g,x);
	}
	cout<<f<<endl<<g;
	return 0;
}
posted @   两只风小鱼  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示