链接: 屠龙宝刀,点击就送
题意: 给出一个数组 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;
}