【题解】导弹拦截

导弹拦截

这道题可以用树状数组、线段树什么的优化

但是我一个都不会

而这道题的数据范围又很大

c++奥赛一本通(meng)上o(n2)的算法过不了

所以本蒟蒻来说一个o(nlogn)的算法

问题转换

第一问很容易就可以想到是求一个最长不上升子序列

但是第二问就需要一个转换的思想了

引理:Dilworth定理:偏序集的最少反链划分数等于最长链的长度

我们可以把问题中需要几组导弹转化成求一个最长上升子序列

证明: 1、首先我们把这些导弹分为s组(s即为所求答案)

可以看出每一组都是一个不升子序列

2、划分完后我们在组一里找一个原序列里以组一的开头点连续的不升子串的最后一个元素,可以知道在组2中一定有一个大与它的点

(如果组二中没有的话,那么组二中最高的导弹高度必然小于这个点,而其他的高度都小于这个高度而且是递减或相等的,那么没有必要再开一个组二了,矛盾,所以不存在找不到比他大的点的情况)

3、以此类推,对于每一个k组(1<=k<n)都可以找到这样的一些点

所以把这些点连起来,就是一条上升子序列。

4、设最长上升子序列长度为l

所求上升子序列为h

那么h<=l

因为最长上升子序列任意两个不在一组内

(如果在同一个组内,则每个组的数不成为一个不生子序列,矛盾)

所以l==h

比较难理解

我们来看组数据

389 207 155 300 299 170 158 65

组一 389 207 155 65 组二 300 299 170 158

步骤一中我们一开始找到的点是1

因为如果找65不好解释,所以我们找原数列里连续的最后一个即155

组二里可以找到300比他大

所以最长上升子序列长度为2==答案

问题求解

到这里我们发现只要求最长不升子序列和最长上升子序列就好了

下面说最长上升子序列的o(nlogn)求法(最长不升子序列同理)

数组a为要求的数列

首先我们开一个数组k

k[lis]记录lis长的上升子序列的最后一个数

len表示最长的长度

初始化len=0,k[0]=-无限

我们可以很轻松的看出k是一个有序的(递增)

如果a[i](1<=i<=n)>k[len]

k[len=1]=i;

不然每次在k里面二分查找第一个大于等于它的数,下标为x

比较大小,k[x]=min(k[x],a[i])

因为我们要求最长的,所以我们要尽可能的让最后一位小(贪心思想)

最后输出len即可

证明

k数组一定是一个有序的上升序列

因为它记录的是长为x的上升序列的最后一位

如果不是上升的,那么它必然可以加入以k[x+1]结尾的上升序列,矛盾

复杂度
每次最坏要二分查找(log len) 一共要n次 len<=n 所以算法复杂度为o(nlogn)

过这个题稳得一批

代码

#include<cstdio> #include<algorithm> using namespace std; const int MAXN=100005; int a[MAXN],n,d1[MAXN],d2[MAXN],len1=1,len2=1; bool cmp(const int &a,const int &b) {return a>b;} int main() { while(scanf("%d",&a[++n])!=EOF) {} n--; d1[1]=a[1],d2[1]=a[1]; //d1从大到小,d2从小到大 for(int i=2;i<=n;i++) { //求最长不上升子序列 if(d1[len1]>=a[i]) d1[++len1]=a[i]; else { //找第一个小于a[i]的数(倒序排) int it=upper_bound(d1+1,d1+1+len1,a[i],cmp)-d1; d1[it]=a[i]; } //求最长上升子序列 if(d2[len2]<a[i]) d2[++len2]=a[i]; else { //找第一个大于等于a[i]的数 int it=lower_bound(d2+1,d2+1+len2,a[i])-d2; d2[it]=a[i]; } } printf("%d\n%d",len1,len2); return 0; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530425.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(33)  评论(0编辑  收藏  举报  
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示