首页 > 其他分享 > [NOIP1999 普及组] 导弹拦截

[NOIP1999 普及组] 导弹拦截

时间:2023-05-18 20:57:48浏览次数:56  
标签:普及 mathit 个数 导弹 NOIP1999 序列 拦截 dp

[NOIP1999 普及组] 导弹拦截

题目描述

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

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

输入格式

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

输出格式

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

样例 #1

样例输入 #1

389 207 155 300 299 170 158 65

样例输出 #1

6
2

提示

对于前 \(50\%\) 数据(NOIP 原题数据),满足导弹的个数不超过 \(10^4\) 个。该部分数据总分共 \(100\) 分。可使用\(\mathcal O(n^2)\) 做法通过。
对于后 \(50\%\) 的数据,满足导弹的个数不超过 \(10^5\) 个。该部分数据总分也为 \(100\) 分。请使用 \(\mathcal O(n\log n)\) 做法通过。

对于全部数据,满足导弹的高度为正整数,且不超过 \(5\times 10^4\)。

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


\(\text{upd 2022.8.24}\):新增加一组 Hack 数据。


解析

第一问

将拦截的导弹的高度提出来成为原高度序列的一个子序列,根据题意这个子序列中的元素是单调不增的(即后一项总是不大于前一项),我们称为单调不升子序列。本问所求能拦截到的最多的导弹,即求最长的单调不升子序列

考虑记 \(dp_{i}\) 表示「对于前 \(i\) 个数,在选择第 \(i\) 个数的情况下,得到的单调不升子序列的长度最长是多少」。于是可以分两种情况:

  • 第 \(i\) 个数是子序列的第一项。则 \(\mathit{dp}_i\gets 1\)。
  • 第 \(i\) 个数不是子序列的第一项。选择的第 \(i\) 个数之前选择了第 \(j\) 个数。根据题意,第 \(j\) 个数的值 \(h(j)\) 应当小于第 \(i\) 个数的值 \(h(i)\)。枚举这样的 \(j\),可以得到状态转移方程:

\[\mathit{dp}_i=\max_{j<i,h(j)\ge h(i)} \{\mathit{dp_j}+1\} \]

综合这两种情况,得到最终的状态转移方程:

\[\mathit{dp}_i=\max\{1,\max_{j<i,h(j)\ge h(i)}\{\mathit{dp}_j+1\}\} \]

image
值得注意的是,第 \(n\) 个数不一定是最长单调不升子序列的最后一项。为了求出答案,我们需要枚举最后一项是哪个:

\[\mathit{ans}=\max_{1\le i\le n}\{\mathit{dp}_i\} \]

直接枚举进行状态转移,时间复杂度显然是 \(\mathcal O(n^2)\)。 下面考虑优化。

记 \(f_i\) 表示「对于所有长度为 \(i\) 的单调不升子序列,它的最后一项的大小」的最大值。特别地,若不存在则 \(f_i=0\)。下面证明:

  • 随 \(i\) 增大,\(f_i\) 单调不增。即 \(f_i\ge f_{i+1}\)。

考虑使用反证法。假设存在 \(u<v\),满足 \(f_u<f_v\)。考虑长度为 \(v\) 的单调不升子序列,根据定义它以 \(f_v\) 结尾。显然我们可以从该序列中挑选出一个长度为 \(u\) 的单调不升子序列,它的结尾同样是 \(f_v\)。那么由于 \(f_v>f_u\),与 \(f_u\) 最大相矛盾,得出矛盾。

因此 \(f_i\) 应该是单调不增的。

现在考虑以 \(i\) 结尾的单调不升子序列的长度的最大值 \(\mathit{dp}_i\)。由于我们需要计算所有满足 \(h(j)>h(i)\) 的 \(j\) 中,\(\mathit{dp}_j\) 的最大值,不妨考虑这个 \(\mathit{dp}_j\) 的值是啥。设 \(\mathit{dp}_j=x\),那么如果 \(h(i)> f_x\),由于 \(f_x\ge h(j)\),就有 \(h(i)>h(j)\),矛盾,因此总有 \(h(i)\le f_x\)。

根据刚刚得出的结论,\(f_i\) 单调不增,因此我们要找到尽可能大的 \(x\) 满足 \(h(i)\le f_x\)。考虑二分。
image
绿色区域表示合法的 \(f_x\)(即 \(f_x\ge h(i)\)),红色区域表示不合法的 \(f_x\)(即 \(f_x< h(i)\)),我们需要找到红绿之间的交界点。

假设二分区域为 \([l,r)\)(注意开闭区间。图上黄色区域标出来了二分区域内实际有效的元素)。每次取 \(m=\frac{l+r}{2}\),如果 \(f_m\) 在绿色区域内,我们就把 \(l\) 移动到此处(\(l\gets m\));否则把 \(r\) 移动到此处(\(r\gets m\))。

当 \(r-l=1\) 时,\(l\) 处位置即为我们需要找的位置。转移 \(\mathit{dp}_i\gets l+1\) 即可。记得更新 \(f\)。但是我们只用更新 \(f_{\mathit{dp}_i}\),这是因为 \(f_1,f_2,\cdots f_{\mathit{dp_i}-1}\) 的大小肯定都是不小于 \(h(i)\) 的。\(f_{\mathit{dp}_i}\) 是最后一个不小于 \(h(i)\) 的位置,\(f_{\mathit{dp}_i+1}\) 则小于 \(h(i)\)。

时间复杂度 \(\mathcal O(n\log n)\),可以通过该问。

第二问

考虑贪心。

从左到右依次枚举每个导弹。假设现在有若干个导弹拦截系统可以拦截它,那么我们肯定选择这些系统当中位置最低的那一个。如果不存在任何一个导弹拦截系统可以拦截它,那我们只能新加一个系统了。

假设枚举到第 \(i\) 个导弹时,有 \(m\) 个系统。我们把这些系统的高度按照从小到大排列,依次记为 \(g_1,g_2,\cdots g_m\)。容易发现我们就是要找到最小的 \(g_x\) 满足 \(g_x\ge h_i\)(与第一问相同,这是可以二分得到的),然后更新 \(g_x\) 的值。更新之后,\(g_1,g_2\cdots g_x\) 显然还是单调不增的,因此不用重新排序;如果找不到符合要求的导弹拦截系统,那就说明 \(g_m<h_i\),直接在后头增加一个就行。

时间复杂度 \(\mathcal O(n\log n)\),可以通过该问。

Code

注:本蒟蒻能力有限,无法AC,谅解一下啦

Method 1

#include<bits/stdc++.h>
using namespace std;
int a[1010],f[1010],b[1010],n,cnt=1,xt[1010];
bool pd[1010];
int main()
{
	while(cin>>a[++n]) f[n]=1;
	n--;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<i;j++)
		{
			if(a[j]>=a[i])
			{
				f[i]=max(f[i],f[j]+1);
			}
		}
	}
	int ans=-1;
	for(int i=1;i<=n;i++)ans=max(ans,f[i]);
	b[1]=a[1];
	for(int i=2;i<=n;i++)
	{
		int minn=30010,x=-1;
		for(int j=1;j<=cnt;j++)
		{
			if(b[j]>=a[i])
			{
				if(b[j]<minn)
				{
					x=j;
					minn=b[j];
				}
			}
		}
		if(x==-1)b[++cnt]=a[i];
		else b[x]=a[i];
	}
	cout<<ans<<'\n'<<cnt;
	return 0;
}

Method 2

#include <bits/stdc++.h>
using namespace std;

int a[0xffffff], x, l, dp[0xffffff], maxn;
int g[0xffffff], cnt;

int main()
{
	while(cin >> x) 
	{
		a[++l] = x;
	}
	for(int i=1;i<=l;i++)
	{
		int k=1;
		while(k<=cnt && g[k]>=a[i]) 
		{
			k++;
		}
		if(k>cnt) 
		{
			g[++cnt]=a[i];
		}
		else g[k] = a[i];
	}
	cout << cnt << endl;
	cnt=0;
	for(int i=1;i<=l;i++)
	{
		int k = 1;
		while(k<=cnt && g[k]<a[i])
		{
			k++;
		}
		if(k>cnt) 
		{
			g[++cnt] = a[i];
		}
		else g[k] = a[i];
	}
	cout << cnt << endl;
}

观察第二问的代码,与第一问进行比较,可以发现这段代码等价于计算最长上升子序列(严格上升,即后一项大于前一项)。这其实是 \(\text{Dilworth}\) 定理(将一个序列剖成若干个单调不升子序列的最小个数等于该序列最长上升子序列的个数),本处从代码角度证明了该结论。

标签:普及,mathit,个数,导弹,NOIP1999,序列,拦截,dp
From: https://www.cnblogs.com/momotrace/p/p1020.html

相关文章

  • 前端工作小结1-拦截器的使用
    1.拦截器综述拦截器的功能是定义在Java拦截器规范。拦截器规范定义了三种拦截点:业务方法拦截,生命周期回调侦听,超时拦截(EJB)方法。在容器的生命周期中进行拦截   publicclassDependencyInjectionInterceptor{      @PostConstruct      publicvoidi......
  • SpringBoot拦截器
    在项目的开发中,在某些情况下,我们需要对客户端发出的请求进行拦截,常用的API拦截方式有Fliter,Interceptor,ControllerAdvice以及Aspect。 上面的图是Spring中拦截机制,请求从Filter-->>Controller的过程中,只要在指定的环节出现异常,可以通过对应的机制进行处理。反之在任何一个环节......
  • spring-boot-starter-validation数据校验全局异常拦截处理(转发)
    原版参考:https://blog.csdn.net/tangyb828/article/details/126884417特殊备注:简要整理笔记,非原著一、引用Maven<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependenc......
  • SpringMVC中多个拦截器的执行顺序
    在SpringMVC中,多个拦截器的执行顺序是由配置文件中拦截器的顺序来决定的。假设我们有3个拦截器:Interceptor1、Interceptor2、Interceptor3,通过配置文件的方式定义拦截器的顺序,例如:<mvc:interceptors><mvc:interceptor><mvc:mappingpath="/**"/><bean......
  • [NOIP2002 普及组] 过河卒
    [NOIP2002普及组]过河卒题目描述棋盘上\(A\)点有一个过河卒,需要走到目标\(B\)点。卒行走的规则:可以向下、或者向右。同时在棋盘上\(C\)点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。棋盘用坐标表示,\(A\)点\((0......
  • [NOIP2014 普及组] 珠心算测验
    [NOIP2014普及组]珠心算测验题目描述珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术。珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及。某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法。他随机生成一个正整数......
  • [NOIP2013 普及组] 表达式求值
    [NOIP2013普及组]表达式求值题目描述给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。输入格式一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“\(+\)”和乘法运算符“$\times$”,且没有括号,所有参与运算的数字均为\(0\)到\(2^{31}-1\)之......
  • [NOIP2005 普及组] 校门外的树
    [NOIP2005普及组]校门外的树题目描述某校大门外长度为\(l\)的马路上有一排树,每两棵相邻的树之间的间隔都是\(1\)米。我们可以把马路看成一个数轴,马路的一端在数轴\(0\)的位置,另一端在\(l\)的位置;数轴上的每个整数点,即\(0,1,2,\dots,l\),都种有一棵树。由于马路上有一......
  • [NOIP2018 普及组] 标题统计
    [NOIP2018普及组]标题统计题目描述凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符?注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。输入格式输入文件只有一行,一个字符串\(s\)。输出格式输出文件只有......
  • [NOIP2004 普及组] 不高兴的津津
    [NOIP2004普及组]不高兴的津津题目描述津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不......