牛客 最大最小(单调栈,区间最大大于最小两倍)

牛客 最大最小(单调栈,区间最大大于最小两倍)_第1张图片

思路:
首先必须明确单调栈的最主要的作用,就是找到每个数左边右边第一个小于大于他的数,如果配上倍增或者二分可以找到小于大于他的第k大数。所有用单调栈的题目都得思考怎么利用这个性质来套题目。

  1. 对于本题,我们可以找到每个数右边第一个大于等于其两倍的数 R 2 [ i ] R2[i] R2[i],小于等于其一半的数 R 3 [ i ] R3[i] R3[i]
  2. 可以找到以每个数为左端点的可行区间的数目,也就是 n − 1 − m a x ( R 2 [ i ] , R 3 [ i ] ) + 1 n-1-max(R2[i],R3[i])+1 n1max(R2[i],R3[i])+1
  3. 但此时有一些数的可行区间没算出来,但他可以与后面的数连接在一起构成可行区间。
  4. 可以想到如果一个区间可行,则把这个区间扩大仍然可行。所以我们还可以维护b[i]代表以第 i i i个数为左端点的可行区间数目,则可以有 b [ i ] = m a x ( b [ i ] , b [ i + 1 ] b[i]=max(b[i],b[i+1] b[i]=max(b[i],b[i+1]。也就是用有值的点来更新没有更新过的点,这个套路也很常见了。
  5. 因为每次只考虑以每个数为左端点的可行区间数目,所以可以保证不会算重。
typedef long long ll;
using namespace std;

const int maxn = 1e5;
const int INF = 0x3f3f3f3f;

struct STK {
    int id,v;
}stk[maxn];
int a[maxn],b[maxn];
int R2[maxn]; //右边第一个大于等于其两倍的数
int R3[maxn]; //右边第一个小于等于其1/2的数

int num[maxn];

int Bin(int top,int v) {
    stk[0].v = 1e9;
    stk[0].id = -1;
    int l = 0,r = top;
    int ans = 0;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(stk[mid].v >= v * 2) {
            l = mid + 1;
            ans = mid;
        } else {
            r = mid - 1;
        }
    }
    return ans;
}

int Bin2(int top,int v) {
    stk[0].v = -1e9;
    stk[0].id = -1;
    int l = 0,r = top;
    int ans = 0;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(stk[mid].v * 2 <= v) {
            l = mid + 1;
            ans = mid;
        } else {
            r = mid - 1;
        }
    }
    return ans;
}
class Solution {
public:
    /**
     *
     * @param array int整型一维数组 array
     * @param arrayLen int array数组长度
     * @return long长整型
     */
    long long MaxMin(int* array, int arrayLen) {
        // write code here
        int n = arrayLen;
        
        for(int i = 0;i < n;i++) {
            R2[i] = R3[i] = n;
            a[i] = array[i];
        }
        
        int top = 0;
        for(int i = n - 1;i >= 0;i--) { //单调递增队列,维护R3
            while(top && stk[top].v > a[i]) {
                top--;
            }
            //        printf("%d \n",top);
            R3[i] = stk[Bin2(top,a[i])].id;
            if(R3[i] == -1) R3[i] = n;
            stk[++top] = {i,a[i]};
        }
        
        top = 0;
        for(int i = n - 1;i >= 0;i--) { //单调递减队列,维护R2
            while(top && stk[top].v < a[i]) {
                top--;
            }
            R2[i] = stk[Bin(top,a[i])].id;
            if(R2[i] == -1) R2[i] = n;
            stk[++top] = {i,a[i]};
        }
        
        ll ans = 0;
        for(int i = 0;i < n;i++) {
            ll r = min(R3[i],R2[i]);
            b[i] = (n - 1 - r + 1);
        }
        for(int i = n - 2;i >= 0;i--) {
            b[i] = max(b[i],b[i + 1]);
        }
        for(int i = 0;i < n;i++) {
            ans += b[i];
        }
        return ans;
    }
};

你可能感兴趣的:(#,单调栈,#,其他比赛题目)