POJ 1759 Garland 二分

一、题目大意

给定一个长度为N的数列H,题目给出H[1]和长度N,已知 H[i]=(H[i+1]+H[i-1])/2+1,每一个H[i]>=0,要我们计算出最小的H[N]。

二、解题思路

对公式进行移项

H[1]固定
H[2]=(H[1]+H[3])/2-1
H[2] + 1 =(H[1]+H[3])/2
H[2]*2 + 2 =H[1]+H[3]
H[3]=H[2]*2+2-H[1]
同理 H[4]=H[3]*2+2-H[2]
那么不难看出,每一个值的取值其实都是一个关于H[2]的增函数,我们只需要对H[2]进行二分,找到所有的H[i]>=0的解即可
H[i]=H[i-1]*2+2-H[i-2]

那么我们对H[2]进行二分,找到满足所有H[i]>=0的最小的H[2],之后计算H[N]输出即可。

这里需要注意的是double二分,需要把eps取的小一点,right取的大一点,left的话取0就行,题目的数据集只有1e3,那么eps取小点不会超时,

三、代码

#include 
using namespace std;
int N;
double H[1007], eps = 0.00000001;
void input()
{
    scanf("%d%lf", &N, &H[1]);
}
// H[1]固定
// H[2]=(H[1]+H[3])/2-1
// H[2] + 1 =(H[1]+H[3])/2
// H[2]*2 + 2 =H[1]+H[3]
// H[3]=H[2]*2+2-H[1]
// 同理 H[4]=H[3]*2+2-H[2]
// 那么不难看出,每一个值的取值其实都是一个关于H[2]的增函数,我们只需要对H[2]进行二分,找到所有的H[i]>=0的解即可
bool judge(double mid)
{
    H[2] = mid;
    for (int i = 3; i <= N; i++)
    {
        H[i] = H[i - 1] * 2.0 + 2.0 - H[i - 2];
        if (H[i] < 0.00)
        {
            return false;
        }
    }
    return true;
}
double calc(double mid)
{
    H[2] = mid;
    for (int i = 3; i <= N; i++)
    {
        H[i] = H[i - 1] * 2.0 + 2.0 - H[i - 2];
    }
    return H[N];
}
void binarySearch()
{
    double left = 0.0, right = 10000000000.0;
    while (left + eps < right)
    {
        double mid = (left + right) / 2;
        if (judge(mid))
        {
            right = mid;
        }
        else
        {
            left = mid;
        }
    }

    printf("%.2f", calc(right));
}
int main()
{
    input();
    binarySearch();
    return 0;
}

你可能感兴趣的:(算法)