洛谷 P1020 导弹拦截(LIS,Dilworth定理)

49 篇文章 0 订阅
45 篇文章 0 订阅

链接:P1020

题目描述

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

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

输入格式:

1行,若干个整数(个数≤100000)

输出格式:

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

输入样例#1:

389 207 155 300 299 170 158 65

输出样例#1:

6
2


分析:

对于第一问:就是求最长非上升子序列长度

而对于第二问:就是求最长非上升子序列个数(将原序列全部拆成最长非升子序列最少有多少个)


Dilworth定理可得 (定义看不懂,直接摆结论 )

在一个序列中,最长下降子序列的个数就等于其最长非下降子序列的长度
       最长非下降子序列的个数就等于其最长下降子序列的长度
       
同理,最长上升子序列的个数就等于其最长非上升子序列的长度
   最长非上升子序列的个数就等于其最长上升子序列的长度


所以对于第二问,只需要求最长上升子序列(严格递增)长度即可。


此外,由于时间要求,应用二分法来解决。



以下代码:

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=100010;
bool cmp(const int &a,const int &b)
{
	return a>b;
}
int main()
{
	int a[maxn],d[maxn];
	int N=1,len;
	while(scanf("%d",&a[N])!=EOF)
		N++;
	N--;
	
	//求最长非上升子序列的长度
	len=1;
	d[1]=a[1];
	for(int i=2;i<=N;i++)
	{
		if(d[len]>=a[i])
			d[++len]=a[i];
		else
			*upper_bound(d+1,d+len+1,a[i],cmp)=a[i];
	}
	printf("%d\n",len);
	
	//求最长上升子序列的长度(即最长非上升子序列的个数)
	len=1;
	d[1]=a[1];
	for(int i=2;i<=N;i++)
	{
		if(d[len]<a[i])
			d[++len]=a[i];
		else
			*lower_bound(d+1,d+len+1,a[i])=a[i];
	}
	printf("%d",len);
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值