2017京东面试编程题保卫方案

2017京东面试编程题 - 保卫方案

题意:

就是在一个环形的地方,排列着一堆山,要求有几对山是可以相互观察的对方的。
相互观察的条件是

  1. 如果相邻,必可以互相观察
  2. 不相邻,但是两者之间没有更高的山,可以互相观察,因为环形的,所以有两个方向,顺时针和逆时针,只要有一个方向可以看到就算可以互相观察。

思路:

我一开始用最简单的暴力,向两边暴力枚举,复杂度差不多是O(n^2),不然是超时的。
看了别人题解发现可以用dp做,复杂度是O(n)。

思路可以说是比较牛批了:

  • 首先要拆环成链,将山的序列改变,第一座山是最高的山。如果第一座是最高的山,那么对于这个环形来说,是不可能通过穿过第一座山去找到可以相互观察的山了,这样就只用讨论正方向的情况了。

  • 其次是统计对于这个序列的L数组和R数组。表示:

First hill to the left of the x, which is strictly higher than x.
First hill to the right of the x, which is strictly higher than x.

  • 生成C数组:

All hills that are as high as x and are located between x and y.

  • 注意left和right统计两次的情况,比如第二高的山在中间的时候

ac代码

#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>

using namespace std;

const int maxn = 1e6 + 5;
int a[maxn], b[maxn], L[maxn], R[maxn], C[maxn];
int n;

int main()
{
	cin >> n;			//输入山的数量
	int ma = -1, mid = 0;			//用于把a[]转化成最高山在第一位数组b[]的临时变量
	for (int i = 0; i < n; i++)			//输入a
	{
		cin >> a[i];
		if (a[i] > ma)
		{
			ma = a[i];
			mid = i;
		}
	}
	mid--;
	for (int j = 1; j <= n; j++)			//将a[]转化成最高的山在第一位的b[],最高的山在b[1]
	{
		b[j] = a[(mid + j) % n];
	}
	L[1] = 1;			//left数组中设定最高的山,下一个比他高的设为1,即自己
	for (int i = 2; i <= n; i++)			//生成left数组
	{
		L[i] = i - 1;			//设定左边的第一座山就比自己高
		while (L[i] > 1 && b[L[i]] <= b[i])				//while语句左移直到找到比自己要高的山
			L[i] = L[L[i]];
	}
	for (int i = n; i >= 1; i--)			//生成right,C数组
	{
		R[i] = i + 1;			//设定右边第一座山就比自己高,并且设定右边的山默认是最高的,因为和最高的山相邻
		while (R[i] <= n && b[R[i]] < b[i])				//while语句右移知道找到跟自己相等或者比自己高的山
			R[i] = R[R[i]];
		if (R[i] <= n && b[R[i]] == b[i])			//如果跟自己一样高,则C[]++
		{
			C[i] = C[R[i]] + 1;
			R[i] = R[R[i]];
		}
	}

	long long ans = 0;				//结果可能很大,用longlong存储
	for (int i = 2; i <= n; i++)			//不用计算最高的山
	{
		ans += C[i] + 2;
		if (L[i] == 1 && R[i] == n + 1)				//此时就是和最高的山形成pair,重复计算了,所以减1
		{
			ans--;
		}
	}
	cout << ans << endl;
    return 0;
}

posted on 2017-07-12 21:12  炮二平五  阅读(1141)  评论(0编辑  收藏  举报

导航