AtCoderのABC    次のABCの問題へ    前のABCの問題へ

ABC279-D Freefall


問題へのリンク


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("10 1");
            //7.7735026919
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("5 10");
            //5.0000000000
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("1000000000000000000 100");
            //8772053214538.5976562500
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long mA;
    static long mB;

    static void Main()
    {
        List<string> InputList = GetInputList();
        long[] wkArr = InputList[0].Split(' ').Select(pX => long.Parse(pX)).ToArray();
        mA = wkArr[0];
        mB = wkArr[1];

        decimal Result = ExecSanbuntansaku();
        Console.WriteLine(Result);
    }

    // 三分探索で極小値を求める
    static decimal ExecSanbuntansaku()
    {
        // AddGを引数として、関数値を返す
        Func<long, decimal> CalcFunc = pAddG =>
        {
            return pAddG * mB + mA / DecimalSqrt(1 + pAddG);
        };

        long L = 0;
        long R = 0;

        // 右端は、2べきで初期値を探す
        decimal FirstVal = CalcFunc(0);
        for (long I = 1; I < long.MaxValue; I *= 2) {
            decimal CurrResult = CalcFunc(I);
            if (CurrResult > FirstVal) {
                R = I;
                break;
            }
        }

        var PairHashSet = new HashSet<string>();
        while (L + 1 < R) {
            long C1 = (L * 2 + R) / 3;
            long C2 = (L + R * 2) / 3;

            decimal C1Val = CalcFunc(C1);
            decimal C2Val = CalcFunc(C2);

            if (C1Val < C2Val) {
                R = C2;
            }
            else {
                L = C1;
            }

            string Hash = string.Format("{0},{1}", L, R);
            if (PairHashSet.Add(Hash) == false) {
                break;
            }
        }

        var MinKouhoList = new List<decimal>();
        for (long I = L; I <= R; I++) {
            MinKouhoList.Add(CalcFunc(I));
        }
        return MinKouhoList.Min();
    }

    // 2分法でdecimal型のsqrtを求める
    static decimal DecimalSqrt(decimal pVal)
    {
        decimal L = 0;
        decimal R = pVal;
        var PairSet = new HashSet<string>();
        while (true) {
            if (PairSet.Add(string.Format("{0},{1}", L, R)) == false) {
                break;
            }
            decimal Mid = (L + R) / 2;
            if (Mid <= pVal / Mid) {
                L = Mid;
            }
            else {
                R = Mid;
            }
        }
        return L;
    }
}


解説

下に凸なグラフなので三分探索してます。

三分探索を始める時の
左端のX座標は、極小値のX座標の左
右端のX座標は、極小値のX座標の右
とする必要があるので、
右端のX座標は、2べきの数を使って、左端の数を超える最小のX座標としてます。