【DP】最长上升子序列

题目链接[NOIP1999 普及组] 导弹拦截 - 洛谷

n方做法不再介绍。

介绍nlogn的做法

假设有一组数据 389 207 155 300 299 170 158 65,求最长下降子序列

依次扫描

389 207 155

扫描到300的时候 更新207为300

扫描到299的时候 更新155为299

【因为300比207更有下降潜质,299比155更有下降潜质】

此时变为389 300 299

剩下170 158 65 依次进去

最后是389 300 299 170 158 65

这个洛谷题目注意,第一次找最长 非严格下降子序列,第二次找 最长 严格上升子序列

upper_bound(x) 寻找第一个大于x的位置,找不到返回数组的尾部元素位置+1的位置

lower_bound(x)寻找第一个大于等于x的位置,找不到返回数组的尾部元素位置+1的位置

注意,默认都是在升序序列上寻找。

如果在降序序列上寻找,需要自定义排序规则cmp。(和sort一种用法)

在降序序列上,upper_bound是第一个小于x的位置

还有一个注意的地方。寻找最长严格下降子序列和寻找最长非严格下降子序列的区别

比如某时刻可能存在 3 2 1和3 2 2 2 2 1的数组。前者需要lowerbound后者需要upperbound。

可以这么考虑。3 2 1 如果严格下降不允许重复的话,此时再来一个2 如果lowerbound肯定会返回

3后面的这个位置。然后就变成了3 2 1;如果允许重复,此时再来一个2,upperbound返回2后面的这个位置(也就是一这个位置),然后就变成了3 2 2

#include<bits/stdc++.h>
using namespace std;
int a[500007];
int cnt;
vector<int>g;
vector<int>gg;
bool cmp(int a,int b){
	return a>b;
}
int main(){
	int x;
	while(cin>>x){
		cnt++;
		a[cnt]=x;
	}
	g.push_back(a[1]);
	gg.push_back(a[1]);
	//先找一下最长 非严格下降子序列
	for(int i=2;i<=cnt;i++){
		int cur=upper_bound(g.begin(),g.end(),a[i],cmp)-g.begin();
		if(cur>=g.size())g.push_back(a[i]);
		else g[cur]=a[i];
	}
	
	//再找一下最长 严格上升
	for(int i=2;i<=cnt;i++){
		int cur=lower_bound(gg.begin(),gg.end(),a[i])-gg.begin();
		if(cur>=gg.size())gg.push_back(a[i]);
		else gg[cur]=a[i];
	} 
	cout<<gg.size();
	return 0;
} 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值