在O(logn)时间内找到数组中离每个数最近而又比它大的数的下标

题目描述

  Farmer Zhao's N cows (1 ≤ N ≤ 1,000,000) are lined up in a row. So each cow can see the nearest cow which is taller than it. You task is simple, given the height (0 < height ≤ 10 9) of each cow lined up in the row, to calculate the distance between each cow and its nearest taller cow, if it is the tallest cow in the row, such distance is regarded as n. You should output the average distance.

输入

  For each test case:
Line 1: One integers, N
Lines 2: N integers. The ith integer is the height of the ith cow in the row.

输出

  The average distance to their nearest taller cow, rounded up to 2 decimals.

示例输入

7
7 6 5 8 6 4 10

示例输出

2.43

y[p]指从p点往前找的第一个比它大的值的下标。

z[p]指从p点往后找的第一个比它大的值的下标。

分析一下为什么能省时间:假设当前点i,那么p从i-1开始往前找起,如果碰到x[p]比x[i]大的,那么就直接跳出循环给y[i]赋值;如果x[p]比x[i]小,提取y[p],那么易知从(y[p],p]这个区间内的所有值都比x[i]小(为什么?假如这个区间内有比x[i]大的值的话,y[p]'取区间内的下标比y[p]显然更优,这就产生矛盾)令p'=y[p],那就可以直接跳过这个区间从p'开始往前找了。

#include<bits/stdc++.h> 
#define ll long long
#define EPS 1e-8  
using namespace std; 
int x[1000005];
int y[1000005];
int z[1000005];
int main(){
	int n;
	while(~scanf("%d",&n)){
		x[0]=2000000000;
		x[n+1]=2000000000;
		for(int i=1;i<=n;++i){
			scanf("%d",&x[i]);
			int p=i-1;
			while(x[p]<=x[i]){ //如果比它小,那么把坐标p移动到更前的y[p]继续找,缩短时间
				p=y[p];
			}
			y[i]=p;
		}
		for(int i=n;i>=1;--i){
			int p=i+1;
			while(x[p]<=x[i]){
				p=z[p];
			}
			z[i]=p;
		}
		double s=0;
		for(int i=1;i<=n;++i){
			if(y[i]==0) y[i]=-2000000000;
			if(z[i]==n+1) z[i]=2000000000;
			s+=min(min(i-y[i],z[i]-i),n);
		}
		printf("%.2f\n",s/n+EPS);  //这题必须加EPS才能过 
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值