题目:
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=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
输出最大距离。
思路:
有三种思路。
第一种:排序。先按值排序,值相等就按位置排序,然后依次遍历
#include <bits/stdc++.h>
using namespace std;
const int N = 50000 + 10, INF = 0x3f3f3f3f;
struct node
{
int x, id;
}a[N];
bool cmp(node a, node b)
{
if(a.x != b.x) return a.x < b.x;
else return a.id < b.id;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i].x), a[i].id = i;
sort(a + 1, a + 1 + n, cmp);
int ans = 0, idx = 0;//idx保存目前遇到的最左端的位置
for(int i = 1; i <= n; i++)
{
if(i == 1 || idx > a[i].id) idx = a[i].id;//当idx大于当前位置的时候,更新最左端位置
else ans = max(ans, a[i].id - idx);//否则更新答案
}
printf("%d\n", ans);
return 0;
}
第二种:二分枚举区间,确定大于等于当前值且最右的位置,这里用了RMQ,用线段树也可以
#include <bits/stdc++.h>
using namespace std;
const int N = 50000 + 10, INF = 0x3f3f3f3f;
int dp[20][N], a[N];
void ST(int n)
{
for(int i = 1; i <= n; i++)
dp[0][i] = a[i];
for(int i = 1; (1<<i) <= n; i++)
for(int j = 1; j <= n - (1<<i) + 1; j++)
dp[i][j] = max(dp[i-1][j], dp[i-1][j+(1<<(i-1))]);
}
int RMQ(int l, int r)
{
int k = log(r - l + 1) / log(2.0);
return max(dp[k][l], dp[k][r-(1<<k)+1]);
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
ST(n);
int ans = 0;
for(int i = 1; i <= n; i++)
{
int l = i+1, r = n, t = 0;
while(l <= r)
{
int mid = (l + r) >> 1;
if(RMQ(mid, r) >= a[i]) t = mid, l = mid+1;
else r = mid-1;
}
ans = max(ans, t - i);
}
printf("%d\n", ans);
return 0;
}
第三种:维护一个单调栈,从栈底到栈顶递减。然后对于每一个值,二分找到小于等于它且最左端的值,更新答案。关于栈要单调递减,这是因为如果大于等于栈顶,可以发现对答案并没有什么贡献
#include <bits/stdc++.h>
using namespace std;
const int N = 50000 + 10, INF = 0x3f3f3f3f;
int a[N], stk[N];
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int ans = 0, top = 0;
for(int i = 1; i <= n; i++)
{
if(top == 0 || a[stk[top-1]] > a[i]) stk[top++] = i;
int l = 0, r = top-1, t = i;
while(l <= r)
{
int mid = (l + r) >> 1;
if(a[stk[mid]] <= a[i]) t = mid, r = mid - 1;
else l = mid + 1;
}
ans = max(ans, i - stk[t]);
}
printf("%d\n", ans);
return 0;
}