题意:
给出一个长度为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;
}