51nod 1153 选择子序列

链接: 屠龙宝刀,点击就送
题意: 给出一个数组 a[ ] 假设下标从0开始

        要你找到一个最长的数组 B

        满足 a[ b[ ] ] 递减,并且,下标在 bi ~ bi+1 间所有数都小于后面那个数(选最大值)

        上面那句话 == 每次选一个最大值,然后只能在已经划分的位置里面继续选值 

        比如案例:      下标: 0  1   2   3   4   5   6  7  8   9  10  11 12   13 14

                              值:   9, 10, 2, -1, 3, -5, 0, -3, 1, 12, 5,  8 , -2 ,  6 , 4

        首先选值 12  对于的 B 数组是下标 9 

        那么下一个数奖 0 --- 8 or 10 --- 14 内选对把

        再选值 10 所对应的 B 数组是下标  1

        那么下一个数只能在 0 --- 1 or 1 --- 9 内选了,因为如果选外面的,那个边界就是之前的最大值,将无法继续满足a[ j ] < a[ b [i + 1]]

思路: 

      常见的就是直接 dfs 返回 max(  dfs( l,mid-1) , dfs(mid + 1,r) ) + 1

      复杂度是 nlogn

      代码: ( 周末填坑 ) 

 

----------------------------------------------------------------------------------------------------------

2019.3.22:

 

/*
   On的做法 : 
   答案肯定可以看作最小值左右扩张 
   15
   4 6 -2 8 5 12 1 -3 0 -5 3 -1 2 10 9
              |  |  | |    |       |
             12 
			                      10
			                3
  		         1
			           0
			        -3
   记录每个值向左向右的最优解,
   然后通过单调队列进行dp 
   对于其中的某一个数 x
   如果我要选 x , 要么它加入前面比他小的成为最大的那个 // 弹掉队内的元素即可 
                  要么它加入单调递减队列成为最小的那个
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 5;

map<int,int> a;
int q[N];
int main() {
	int n,x,l = 1,r = 0,ans = 0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d",&x);
		int Max = 0; 
		while(l <= r && q[r] < x) {
			Max = max(Max,a[q[r]]);
			r --;
		}
		Max = max(Max,r - l + 1) + 1;
		q[++r] = x;
		a[x] = Max;
		ans = max(ans,Max);
	}
	cout << ans;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值