首页 > 其他分享 >导弹拦截

导弹拦截

时间:2024-10-15 16:21:21浏览次数:7  
标签:int max 导弹 exist 拦截 dp

题目

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

输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统
\(\\\)
经典的DP,适合打好基础
\(\\\)

第一问

求最长不下降子序列
定义\(dp_i\) 为以第\(i\)个导弹高度为结尾,拦截的最多的导弹
\(h[i]\)为第\(i\)个导弹高度
\(\\\)
所以根据dp的通常思考方式,寻找\(dp_i\)之间的关系
\(\\\)
如果\(\exist j<i 且 h[j]>h[i]\) 那么这两个导弹就能被同一个导弹拦截系统
\(\\\)
同理\(\exist j<i 且 h[j]>h[i]\) 那么\(dp_i=dp_j+1\)
\(\\\)
此时以第\(j\)个导弹高度为结尾的序列长度为\(dp_j\),而\(h[j]>h[i]\)
也可以拦截第\(i\)个导弹
\(\\\)
而\(dp_i可以由多个dp_j得到,所以\displaystyle dp_i=max_{j<i, h[j]>h[i]} (dp_i,dp_j+1)\)

第二问

求最少的不下降子序列个数
贪心,当前已有的系统拦截不到,就增加系统
定义\(dp_i\)为第i个导弹高度为结尾的第\(dp_i\)个系统
\(\\\)
如果\(\exist j<i 且 h[j]<h[i]\) 那么这两个导弹就不能被同一个导弹拦截系统,需要新开一个系统,且新系统的拦截最后一个导弹为h[i]
如果\(\exist j<i 且 h[j]>h[i]\) 那么这个导弹就可以被之前拦截h[j]的导弹拦截,就不需要开新系统
\(\\\)
同理\(\exist j<i 且 h[j]<h[i]\) 那么\(dp_i=dp_j+1\)
\(\\\)
而\(dp_i可以由多个dp_j得到,所以\displaystyle dp_i=max_{j<i, h[j]<h[i]} (dp_i,dp_j+1)\)
\(\\\)
--小疑问:可能会有人问,为什么求最少的不下降序列个数反而还要取max
答:这样取max才能使每一个导弹被拦截

\(\\\)

CODE

#include<cstring>
#include<iostream>

using namespace std;
int n;
int m[100000+10];
int f[100000+10];
int ans[100000+10];
int main(){
	ios::sync_with_stdio(0);
	int a;
	int len=0;
	memset(ans,0,sizeof(ans));
	while(cin>>a){
		m[++len]=a;
		f[len]=1;
	} 
	int maxx=0; 
	for(int i=2;i<=len;++i){
		for(int j=1;j<i;++j)
			if(m[i]<=m[j]) 
				f[i]=max(f[i],f[j]+1);
		maxx=max(f[i],maxx);
	}
	cout<<maxx<<endl;
	maxx=0;
	memset(f,1,sizeof(f));
	
	for(int i=1;i<=len;++i){
		f[i]=1;
		for(int j=1;j<i;++j)
			if(m[j]<m[i])
				f[i]=max(f[i],f[j]+1);
		maxx=max(maxx,f[i]);//有可能后面的导弹已经被前面已有的系统拦截了,不需要开新系统,而此时找到的最大值即是刚好拦截所有导弹的系统数量
	}
	cout<<maxx<<endl;
	return 0;
}

以上的code可以过1e5级别的数据

而此题可以考虑优化

优化

1.第一问

根据\(\displaystyle dp_i=max_{j<i, h[j]>h[i]} (dp_i,dp_j+1)\)

\(\\\)
我们有一定的时间在寻找\(max(dp_j+1)\),这导致了我们每次寻找时的复杂度为\(O(N)\)
根据题目的复杂度要求,我们应该考虑\(log_{2}N\)复杂度的寻找方法
对于\(\forall dp_j\in[0,n] \ and \ n<1e5\)
而且我们只需要最大值
\(\\\)
这时如果我们利用桶排序的思想,就能快速查找,并且存最大值

令\(f[x]\)为长度为x的最长不上升子序列的末端高度
\(\\\)
对于\(\forall x>1 , \exist y<x,f[x]<f[y]\)(单调递减)
\(\\\)
所以当我们考虑\(h[i]\)时,我们只需要在已知长度中找\(f[j]<=h[i](j为符合该条件的最大值),f[j+1]=h[i]\)
\(\\\)
而由于这种序列是单调递减,所以二分查找就可以,复杂度就降到\(O(log_2N)\)

第二问

\(\displaystyle dp_i=max_{j<i, h[j]<h[i]} (dp_i,dp_j+1)\)
令\(f[x]\)为第x个系统的拦截的末端高度
\(\\\)
对于\(\forall x>0, \exist y>x,f[x]<f[y]\)(单调递增)

所以对于\(h[i]\),开一个新系统,我们只需要考虑,不\(\exists x,f[x]>h[i]\),此时没有系统拦截的高度超过当前导弹,所以需要一个新系统

#include<bits/stdc++.h>

using namespace std;
int n=0;
const int maxn=1e5+10;
int t;
int h[maxn],f[maxn];

int main(){
    while(~scanf("%d",&h[++n])); --n;
	t=1;memset(f,0,sizeof(f));
	//f[i]表示长度i的序列结尾的高度 
	for(int i=1;i<=n;++i){
		int l=1,r=t;//当前长度的范围
		
		while(l<=r){//查找该高度可以拼接的最长长度 
			int mid=(l+r)>>1;
			if(f[mid]>=h[i]) l=mid+1;
			else r=mid-1;
		}
		//最后二分找到的 f[l]<h[i] && f[r]>=h[i] && r+1=l 
		//所以 f[l]=h[i]
		//若长度增加,r=t,l=t+1; //最大长度增加
		if(l>t)	t=l; 
		f[l]=h[i];//长度l的最长不上升序列结尾是h[i] 
	}
	printf("%d\n",t);
	t=0;memset(f,0,sizeof(f));
	for(int i=1;i<=n;++i){
		int l=0,r=t;//当前系统数范围
		while(l<=r){//查找该高度可以拼接的系统,找不到,就新增系统 
			int mid=(l+r)>>1;
			if(f[mid]<h[i]) l=mid+1;
			else r=mid-1;
		}
		if(l>t) t=l;
		f[l]=h[i]; 
	} 
	printf("%d\n",t);
	return 0;
}

标签:int,max,导弹,exist,拦截,dp
From: https://www.cnblogs.com/guiyou/p/18461012

相关文章

  • 过滤器拦截器拦截了request后,controller的@RequestBody 无法获取request内容,报错 Requ
    SpringMVC的拦截器、过滤器、Controller之间的关系 众所周知所有的post请求中的body参数是已流形式存在的,而流数据只能读取一次(为啥看这里),如果在拦截器和过滤器中需要对post参数进行处理的话,就会报Requiredrequestbodyismissing异常。既然知道原因,那只要能将流保存起来......
  • 过滤器和拦截器的区别是什么?
    首先,过滤器和拦截器都可以在请求的过程中插入一手,也可以进行拦腰截断。请求过程:当一个请求进来,先交给Web服务器提供的过滤器,来到Servlet,同时会有一个叫做DispatcherServlet的Servlet进行执行,在DispatcherServlet中就会调用我们的拦截器,再由DispatcherServlet分发给对应的Contro......
  • Spring 过滤器 拦截器 监听器 Aop
    目录Spring过滤器拦截器监听器Aop1.过滤器2.拦截器3.监听器4.Aop5.参考文档Spring过滤器拦截器监听器Aop1.过滤器1.简介 过滤器Filter用于对数据进行过滤和预处理 过滤器只能在请求前后使用 依赖于servlet容器基于函数回调实现其生命周期由servlet容器管......
  • springboot如何做token的拦截校验
    1、新建一个拦截类@ComponentpublicclassLoginInterceptorimplementsHandlerInterceptor{@AutowiredprivateJwtUtiljwtUtil;@Value("${oaTokenKeyword}")privateStringoaTokenKeyword;@OverridepublicbooleanpreHandle(Http......
  • 【Spring Security OAuth2】- 【使用Spring MVC开发RESTful API】 使用切片拦截rest服
    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬学习必须往深处挖,挖的越深,基础越扎实!阶段1、深入多线程阶段2、深入多线程设计模式阶段3、深入juc源码解析阶段4、深入jdk其余源码解析......
  • 拦截器实现拦截到人员的id
    WebConfig.WebConfig(配置拦截器)@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@BeanpublicCrewInterceptorcrewInterceptor(){returnnewCrewInterceptor();}/*@AutowiredprivateCrewInterceptorcrewInterc......
  • P1020 [NOIP1999 提高组] 导弹拦截
    P1020[NOIP1999提高组]导弹拦截参考材料需要抽象一下,第一问就可以抽象为最长不上升子序列,第二问可以抽象为最长上升子序列长度。就如下图的情况:然后可以先\(n^2\)做法做,因为\(n\ge100000\)所以要滚动数组,求最长不上升子序列可以反向从n开始递推。我是n^2我不好......
  • SQL注入拦截工具-动态order by
    ......
  • MyBatis拦截器
    一.JDBC的执行流程(面试题一)JBDC的底层主要是三个接口对象,Connection、Statement、ResultSet。Connection用于建立与数据库的连接,Statement用于向数据库发送sql语句,ResultSet用于封装sql查询语句的结果。原始的JDBC操作数据库主要有以下几个步骤:1.注册驱动使用Class.f......
  • 接上文实现SpringSecurity,拦截器的实现
    实现拦截器有图片可知,在上篇文章我们重写了UserDetailsManager,现在我们来进行之后的操作在UserDetailsManager中我们可以调动数据库去进行一个账号密码的校验之后我们这样设置拦截器进行一个token获取存储在usernamePasswordAuthenticationFilter这一层中,有,则存储在Secur......