导弹拦截--最长子序列问题(nlogn做法)

本文介绍了如何使用nlogn时间复杂度的方法解决最长子序列问题,通过动态数组和lower_bound/upper_bound操作,分别处理最长上升子序列和最长不降子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第二遍写这道题,写写新的体会,对于最长子序列问题虽然说可以用dp解决,但是这是n方的做法,同时,存在nlogn的更优的做法(更像是贪心一类的),可以自己想想

传送门:

个人想法:对于二分的时候

                  我认为 最长上升子序列用lower_bound   最长不降用upper_bound                            

                              最长下降子序列用lower_bound   最长不升用upper_bound

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int f[N]={1};
int len;
int b[N];
int c[N];
int lenn;

int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int k,cnt=0;
	while(cin>>k){
		a[++cnt]=k;//一共cnt个
	}
	c[0]=1e9;
	for(int i=1;i<=cnt;++i){
		if(a[i]<=c[lenn]){
			c[++lenn]=a[i];//构造一个动态数组,如果某一个数字小于尾数,就把他放在最后
		}
		else{
			*upper_bound(c+1,c+1+lenn,a[i],greater<int>())=a[i];
//学习一下书写形式   这里的意思是,找到第一个小于a[i]的数字并且将其换掉  
//比如说 我有5 3 2 1 现在要插入一个4  这时候 我就替换成5 4 2 1  如此一来就会更优
//这里之所以可以用upper 正是因为他是最长不升
//可以证明,只有出现接着5 4的序列 才会用到它,要不然并不会影响对后面数字的判断
		}
	}
	cout<<lenn<<endl;
	
	b[0]=-1e9;
	for(int i=1;i<=cnt;++i){
		if(a[i]>b[len]){
			b[++len]=a[i];
		}
		else{
			*lower_bound(b+1,b+1+len,a[i])=a[i];
//如果原来是 1 5 7 8  现在插入一个5   就变成1 5 7 8(这里是上升子序列,所以不能用upper_bound,我认为如果是最长不降是可以使用的)
		}
	}
	cout<<len<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值