51nod 40 选择子序列 单调栈+DP

题意:长度为n的序列a.每个数都不相同. 
找到一个序列b 0<=b[i]<n.并且序列b满足: A[b[0]]> A[b[1]]> ...A[b[k]]. 
并且:A[j]<A[b[i+1]]. (min(b[i],b[i+1]) <j <max(b[i],b[i+1])) 
n<=5e4,a[i]<=1e9 问序列b的长度最长为?



a[b[i]]要大于(a[b[i]]~a[b[i-1]])之间的数. 
选下一个数,可以在上一个数的左右两边 而且不知道要选哪一个 不好处理.


先保存每个数的下标 然后将序列按照权值从大到小排序.
设dp[i]为以排序后下标i结尾 选出最长序列的长度.
因为j<i a[j]>a[i] 如果 b[j]~b[i]之间没有出现以前出现过的下标则.
dp[i]=max(dp[i],dp[j]+1) O(n^2 logn).


..1.11. X..1..1...
对于某个下标编号为X 其实它只能跟在X左边第一比它大的和X往右第一个比它大的后面.

用单调栈预处理后 在DP一次即可 O(N+NlogN).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
struct node{
	int x,id;
}a[N];
bool cmp(node a,node b)
{
	return a.x>b.x;
}
int n,dp[N],c[N];
int le[N],rg[N];
stack<int> s;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].x,a[i].id=i;
		while(!s.empty()&&a[s.top()].x<a[i].x)
			rg[s.top()]=i,s.pop();
		if(!s.empty())
			le[i]=s.top();	
		s.push(i);
	}
	sort(a+1,a+1+n,cmp);
	int res=1;
	for(int i=1;i<=n;i++)
	{
		int j=a[i].id,x=le[j],y=rg[j];
		dp[j]=1;
		if(x)
			dp[j]=max(dp[j],dp[x]+1);
		if(y)
			dp[j]=max(dp[j],dp[y]+1);
		res=max(res,dp[j]);
	}
	printf("%d\n",res);
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值