找山坡
题意:
母牛哥在电脑面前坐久了,想站起来看看窗外的小山坡,于是就想出了这个问题:
给定一个大小为n的数组a,序号从1开始,
计算:max{ R - L | 1 <= L <= R <= n, a[L] == a[R], 对于所有i (L <= i <= R), 满足a[i] >= a[L] }.
也就是找到两个坐标,这两个坐标的值相等,并且他们之间的值都大于等于这两个坐标上的值.
这两个坐标相减最大能是多少.
示例
输入
5 1 2 3 2 1
输出
4
(当L=1,R=5时,满足题目条件的最优解,答案为R-L=5-1=4)
数据范围:
1<=n<=1e6
0<=a[i]<=1e9
思路:
法一:用单调栈维护一个单调递增区间,然后当栈顶与当前的数相等时取坐标差,比较得最大值。
for(int i=1; i<=n; i++){ a[i]=read(); while(top && a[stk[top]]>a[i]) top--; //此时存的是单调递增 if(!top) stk[++top]=i; else{ if(a[stk[top]]==a[i]) ans = max(ans, i-stk[top]); else stk[++top]=i; } }
思路二:这是我最开始的思路,用双指针维护,思路其实同法一,但是双指针维护的 l 和 r 的关系,应该维护的是一个单调栈而不是单调队列,故想法错误。
//错误的代码 for(int l=1,r=1; r<=n; r++){ while(l<r && a[r]<a[l]) l++; if(a[r]==a[l]) ans = max(ans, r-l); } /* eg: 1 2 4 5 3 10 1 */
法二:
用RMQ 存区间最小值,然后离散化存某个数上一次出现的位置。扫描一遍,如果该数已出现过,就检测两个数的区间内最小值是否为这个数。
可以用线段树维护区间最值,也可以用ST表。
(看rank榜上别人的思路,自己就没有写一遍了hh)