51Nod - 1272 单调队列 + 二分

题意:

给出一个长度为N的整数数组A,对于每一个数组元素,如果他后面存在大于等于该元素的数,则这两个数可以组成一对。每个元素和自己也可以组成一对。例如:{5, 3, 6, 3, 4, 2},可以组成11对,如下(数字为下标):
(0,0), (0, 2), (1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (3, 3), (3, 4), (4, 4), (5, 5)。其中(1, 4)是距离最大的一对,距离为3。
Input
第1行:1个数N,表示数组的长度(2 <= N <= 50000)。
第2 - N + 1行:每行1个数,对应数组元素Ai(1 <= Ai <= 10^9)。
Output
输出最大距离。
Input示例
6
5
3
6
3
4
2
Output示例
3

思路:

这题应该还有O(n)的做法,不过我暂时想到的还是O(nlogn),这里只介绍我的想法,思路如下:
对于一个数想知道它之前最远的比它小的数,那么遍历的过程中,将遍历过的数字存下来到数组b中,越小越靠前的数越有价值,很显然,如果比前面的数都大且靠后的数就没有价值,设这样的数为x,假如在x之后有一个数z比x大,他们可以凑成一对,那么鉴于x的条件一定能在x之前找到一个y比x小,这样(y,z)配对效果更好。
所以数组b必须保证从大到小的单调性:
如果当前a[i]小于等于队尾b[cnt],那么很显然它是目前最小的一个数,不可能和之前的数配对,所以直接入队。
否则,就要在数组b中二分找到第一个小于a[i]的数,通过查询map得到下标,从而更新ans。
思路介绍是从左往右。为了便于利用lower_bound,代码是从右往左反着遍历的。

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e4 + 10;

int a[MAXN], b[MAXN];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    map <int, int> mp;
    int cnt = 0, ans = 0;
    for (int i = n; i >= 1; i--) {
        if (b[cnt] < a[i]) {
            b[++cnt] = a[i];
            mp[a[i]] = i;
            continue;
        }
        int pos = lower_bound(b + 1, b + 1 + cnt, a[i]) - b;
        ans = max(ans, mp[b[pos]] - i);
    }
    printf("%d\n", ans);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值