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座標としてます。