AOJ本の読書メモ
AOJ
次のAOJの問題へ
前のAOJの問題へ
AOJ 0600 バームクーヘン
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("6");
WillReturn.Add("1");
WillReturn.Add("5");
WillReturn.Add("4");
WillReturn.Add("5");
WillReturn.Add("2");
WillReturn.Add("4");
//6
}
else if (InputPattern == "Input2") {
WillReturn.Add("30");
WillReturn.Add("1");
WillReturn.Add("34");
WillReturn.Add("44");
WillReturn.Add("13");
WillReturn.Add("30");
WillReturn.Add("1");
WillReturn.Add("9");
WillReturn.Add("3");
WillReturn.Add("7");
WillReturn.Add("7");
WillReturn.Add("20");
WillReturn.Add("12");
WillReturn.Add("2");
WillReturn.Add("44");
WillReturn.Add("6");
WillReturn.Add("9");
WillReturn.Add("44");
WillReturn.Add("31");
WillReturn.Add("17");
WillReturn.Add("20");
WillReturn.Add("33");
WillReturn.Add("18");
WillReturn.Add("48");
WillReturn.Add("23");
WillReturn.Add("19");
WillReturn.Add("31");
WillReturn.Add("24");
WillReturn.Add("50");
WillReturn.Add("43");
WillReturn.Add("15");
//213
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long[] GetSplitArr(string pStr)
{
return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => long.Parse(pX)).ToArray();
}
static long[] mRunSumArr;
static long mHalfLength;
static long UB_Half;
static long UB_Twice;
static void Main()
{
List<string> InputList = GetInputList();
List<long> AList = InputList.Skip(1).Select(pX => long.Parse(pX)).ToList();
long SumA = AList.Sum();
mHalfLength = AList.Count;
UB_Half = AList.Count - 1;
// 環状の対応
AList.AddRange(AList);
// 累積和を求める
mRunSumArr = AList.ToArray();
UB_Twice = mRunSumArr.GetUpperBound(0);
for (long I = 1; I <= UB_Twice; I++) {
mRunSumArr[I] += mRunSumArr[I - 1];
}
long L = 0;
long R = SumA;
while (L + 1 < R) {
long Mid = (L + R) / 2;
if (CanAchieve(Mid)) {
L = Mid;
}
else {
R = Mid;
}
}
Console.WriteLine(L);
}
// 3つともK以上にできるかを返す
static bool CanAchieve(long pK)
{
for (long I = 0; I <= UB_Half; I++) {
bool Result = CanAchieveHelper(I, I + mHalfLength - 1, pK);
if (Result) return true;
}
return false;
}
// MinIndとMaxIndとKを引数とし、3つともK以上にできるかを返す
static bool CanAchieveHelper(long pMinInd, long pMaxInd, long pK)
{
// 1つめの分割
long CurrInd = pMinInd;
long NeedRunSum = pK;
if (CurrInd > 0) {
NeedRunSum += mRunSumArr[CurrInd - 1];
}
int ResultInd1 = ExecNibunhou_LowerBound(NeedRunSum, mRunSumArr);
if (ResultInd1 == -1) return false;
if (ResultInd1 > pMaxInd) return false;
CurrInd = ResultInd1 + 1;
if (CurrInd > pMaxInd) return false;
// 2つめの分割
NeedRunSum = pK;
if (CurrInd > 0) {
NeedRunSum += mRunSumArr[CurrInd - 1];
}
int ResultInd2 = ExecNibunhou_LowerBound(NeedRunSum, mRunSumArr);
if (ResultInd2 == -1) return false;
if (ResultInd2 > pMaxInd) return false;
CurrInd = ResultInd2 + 1;
if (CurrInd > pMaxInd) return false;
// 3つめの分割
NeedRunSum = pK;
if (CurrInd > 0) {
NeedRunSum += mRunSumArr[CurrInd - 1];
}
int ResultInd3 = ExecNibunhou_LowerBound(NeedRunSum, mRunSumArr);
if (ResultInd3 == -1) return false;
if (ResultInd3 > pMaxInd) return false;
return true;
}
// 二分法で、Val以上で最小の値を持つ、添字を返す
static int ExecNibunhou_LowerBound(long pVal, long[] pArr)
{
if (pArr.Length == 0) return -1;
// 最後の要素がVal未満の特殊ケース
if (pVal > pArr.Last()) {
return -1;
}
// 最初の要素がVal以上の特殊ケース
if (pVal <= pArr[0]) {
return 0;
}
int L = 0;
int R = pArr.GetUpperBound(0);
while (L + 1 < R) {
int Mid = (L + R) / 2;
if (pArr[Mid] >= pVal) {
R = Mid;
}
else {
L = Mid;
}
}
return R;
}
}
解説
環状なので、最初に2つ繋げてます。
それから累積和を求め、
始点を全探索し、LowerBoundメソッドを使ってます。