洛谷「Daily OI Round 3」Pigeon 题解

题目

题面戳我哦~

题意概括:给定一个序列,我们需要找出一个值,使序列每一项到我们找的这个值的距离(就是两个数的绝对值,我们可以想象为坐标轴上的距离)都比它前一项到我们找的这个值的距离大。

分析

看到题目的第一眼我想到了二分,但是答案好像不具备单调性,无法判断到底是往左边继续二分还是往右边继续二分。

虽然说二分不可取反正我没想到二分怎么做,但是这启示了我们一点:我们可以通过缩小边界来确定我们要找的值

考虑如何缩小边界,我们不妨进行分类讨论。在此之前,先将一些概念定义一下,以方便后续讨论。

r e s res res 为我们需要找的值, a i a_i ai 为当前项, a i − 1 a_{i-1} ai1 为当前项的前一项, l l l 为我们所确定的左边界, r r r 为我们所确定的右边界。对于 i = 1 i=1 i=1 的这种边界情况我们暂时不考虑,这是写代码时才需要注意的。

  1. a i > a i − 1 a_i>a_{i-1} ai>ai1 时,画个数轴我们可以发现, r e s res res 一定会在这两项的中点的左侧,即 r e s res res 一定小于 a 1 + a i − 1 2 \frac{a_1+a_{i-1}}{2} 2a1+ai1,那么我们的右边界就可以进行缩小了。

  2. a i < a i − 1 a_i<a_{i-1} ai<ai1 时,同样的画个数轴,我们可以发现, r e s res res 一定会在这两项的中点的右侧,即 r e s res res 一定大于 a i + a i − 1 2 \frac{a_i+a_{i-1}}{2} 2ai+ai1,那么我们的左边界就可以进行缩小了。

好了,我们已经知道有解该怎么解决了,那么无解怎么办呢?

无解同样也很简单。

  1. 如果 l > r l>r l>r 就说明取不到任何值了,可以退出去了。
  2. 或者 r − l ≤ 1 0 − 6 r-l\le10^{-6} rl106 这个时候区间已经很小很小了,而题目已经告诉我们我们要找的 r e s res res 小数点后面只有 3 3 3 位,所以这个时候也是不满足了。
  3. 当然我们不能漏掉一种很重要的情况,那就是当 a i a_i ai a i − 1 a_{i-1} ai1 相等时,这个时候无论我们怎么取值,这两项到取值的距离都相等,这也是一种无解情况。

无解和有解我们都知道怎么做了,我们开始写代码。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5+10;
const double eps = 1e-6;	//精度

int n;
int a[N];
double l = -2e9 , r = 2e9;	//l和r都是小数,用double存

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	
	cin >> n;
	for (int i=1 ; i<=n ; i++)
	{
		cin >> a[i];
	}
	
	for (int i=2 ; i<=n ; i++)
	{
		if (l>=r || r-l<=eps || a[i]==a[i-1])	//3种无解情况的判断
		{
			cout << "pigeon" << endl;
			return 0;
		}
		if (a[i-1]>a[i])	//有解时缩小左边界
		{
			double mid = (double)(a[i-1]+a[i])/2;
			l = max(mid , l);
		}
		if (a[i-1]<a[i])	//有解时缩小右边界
		{
			double mid = (double)(a[i-1]+a[i])/2;
			r = min(mid , r);
		}
	}
	
	if (l>=r || r-l<eps)	//由于我们是在循环开始的时候判断的,
    					  //所以我们可能会漏掉最后一项和倒数第二项让边界不满足的情况
	{
		cout << "pigeon" << endl;
		return 0;
	}
	cout << "lovely\n";		//别忘记输出这个了
	cout << fixed << setprecision(7) << l+eps << endl; 	//题目说不能保留超过10位小数,那我们保留7位
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值