Divide and conquer:Garland(POJ 1759)

                 

                   挂彩灯

  题目大意:就是要布场的时候需要挂彩灯,彩灯挂的高度满足:

H1 = A 
Hi = (Hi-1 + Hi+1)/2 - 1, for all 1 < i < N 
HN = B 
Hi >= 0, for all 1 <= i <= N 

  现在已知彩灯的个数和第一个彩灯挂的高度,要你求最后一个彩灯最低能挂多高?

  这又是个最大化最小值的问题,从题目中我们可以看到递推公式的影子,其实这一题我们只要把答案二分,然后根据递推公式写出通项公式,一个灯一个灯看是否有低于0的高度就好

  递推公式转通项公式,这一题可以直接看出来,移项我们就可以得出

    A(i)-A(i-1)=A(i-1)-A(i)-2

    两边同时加上-2i可得,

    A(i)-A(i-1)-2i=A(i-1)-A(i)-2(i-1)

    也就是A(i)-A(i-1)-2i=C

    移项就可以得出变等差公式的递推,最后解得:

    A(i)=C*(i-1)+i*(i-1)+A(1)

    现在A1是已知的,我们只用不断二分枚举A(i)得到常数C,然后一个一个数看是否有小于0的即可

  

#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;

bool Solve(const double, const double, const int);

int main(void)
{
    int lamps_sum;
    double A_height, mid, lb, ub;

    while (~scanf("%d%lf", &lamps_sum, &A_height))
    {
        lb = 0; ub = (double)INT_MAX;
        for (int i = 0; i < 100; i++)//100次的精度很高了
        {
            mid = (ub + lb) / 2;
            if (Solve(A_height, mid, lamps_sum)) ub = mid;
            else lb = mid;
        }
        printf("%.2f\n", lb);
    }

    return EXIT_SUCCESS;
}

bool Solve(const double A1, const double x, const int num_sum)
{
    //递推公式通项:Ai = C*(i - 1) + i*( i - 1 ) +A1
    double C = (x - A1 - num_sum*(num_sum - 1)) / (num_sum - 1);

    for (int i = 1; i <= num_sum; i++)//所有的灯都要触地以上
        if (C*(i - 1) + i*(i - 1) + A1 < 0)
            return false;
    return true;
}

 

 

posted @ 2016-01-27 20:25  PhiliAI  阅读(259)  评论(0编辑  收藏  举报