AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC095-D Static Sushi
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("3 20");
WillReturn.Add("2 80");
WillReturn.Add("9 120");
WillReturn.Add("16 1");
//191
}
else if (InputPattern == "Input2") {
WillReturn.Add("3 20");
WillReturn.Add("2 80");
WillReturn.Add("9 1");
WillReturn.Add("16 120");
//192
}
else if (InputPattern == "Input3") {
WillReturn.Add("1 100000000000000");
WillReturn.Add("50000000000000 1");
//0
}
else if (InputPattern == "Input4") {
WillReturn.Add("15 10000000000");
WillReturn.Add("400000000 1000000000");
WillReturn.Add("800000000 1000000000");
WillReturn.Add("1900000000 1000000000");
WillReturn.Add("2400000000 1000000000");
WillReturn.Add("2900000000 1000000000");
WillReturn.Add("3300000000 1000000000");
WillReturn.Add("3700000000 1000000000");
WillReturn.Add("3800000000 1000000000");
WillReturn.Add("4000000000 1000000000");
WillReturn.Add("4100000000 1000000000");
WillReturn.Add("5200000000 1000000000");
WillReturn.Add("6600000000 1000000000");
WillReturn.Add("8000000000 1000000000");
WillReturn.Add("9300000000 1000000000");
WillReturn.Add("9700000000 1000000000");
//6500000000
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long mC;
struct XVInfoDef
{
internal long X;
internal long V;
}
static List<XVInfoDef> mXVInfoList = new List<XVInfoDef>();
static int UB;
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();
SplitAct(InputList[0]);
mC = wkArr[1];
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
XVInfoDef WillAdd;
WillAdd.X = wkArr[0];
WillAdd.V = wkArr[1];
mXVInfoList.Add(WillAdd);
}
UB = mXVInfoList.Count - 1;
// X座標の昇順にソートしておく
mXVInfoList = mXVInfoList.OrderBy(pX => pX.X).ToList();
var AnswerKouhoList = new List<long>();
long Kouho01 = DeriveKouho01();
AnswerKouhoList.Add(Kouho01);
long Kouho02 = DeriveKouho02();
AnswerKouhoList.Add(Kouho02);
long Kouho03 = DeriveKouho03();
AnswerKouhoList.Add(Kouho03);
Console.WriteLine(AnswerKouhoList.Max());
}
// 解候補01 右にひらすら進んだ時の最大値を返す
static long DeriveKouho01()
{
long CurrVal = 0;
long CurrPos = 0;
long Answer = 0;
foreach (XVInfoDef EachXVInfo in mXVInfoList) {
CurrVal -= EachXVInfo.X - CurrPos;
CurrPos = EachXVInfo.X;
CurrVal += EachXVInfo.V;
Answer = Math.Max(Answer, CurrVal);
}
return Answer;
}
// 解候補02 左にひらすら進んだ時の最大値を返す
static long DeriveKouho02()
{
long CurrVal = 0;
long CurrPos = mC;
long Answer = 0;
foreach (XVInfoDef EachXVInfo in mXVInfoList.AsEnumerable().Reverse()) {
CurrVal -= CurrPos - EachXVInfo.X;
CurrPos = EachXVInfo.X;
CurrVal += EachXVInfo.V;
Answer = Math.Max(Answer, CurrVal);
}
return Answer;
}
// 解候補03 左に進んでから、原点に戻って、右に進む時の最大値を返す
static long DeriveKouho03()
{
long[] RunMaxArr1 = DeriveRunMaxArr(false);
long[] RunMaxArr2 = DeriveRunMaxArr(true);
// 左にどこまで進むかを全探索
long CurrVal = 0;
long CurrPos = mC;
long Answer = 0;
for (int I = UB; 1 <= I; I--) {
CurrVal -= CurrPos - mXVInfoList[I].X;
CurrPos = mXVInfoList[I].X;
CurrVal += mXVInfoList[I].V;
int LeftLen = UB - I + 1;
long BackCost = mC - CurrPos;
// 左に移動してから、右に移動する場合
long RunMax1 = RunMaxArr1[UB - LeftLen];
long AnswerKouho1 = CurrVal - BackCost + RunMax1;
// 右に移動してから、左に移動する場合
long RunMax2 = RunMaxArr2[UB - LeftLen];
long AnswerKouho2 = CurrVal + RunMax2;
Answer = Math.Max(Answer, AnswerKouho1);
Answer = Math.Max(Answer, AnswerKouho2);
}
return Answer;
}
// 原点からの最大値を求め、累積最大値も求める。移動コストの2倍フラグも持つ
static long[] DeriveRunMaxArr(bool pMoveCost2)
{
long[] WillReturn = new long[mXVInfoList.Count];
long CurrVal = 0;
long CurrPos = 0;
long CurrValMax = long.MinValue;
for (int I = 0; I <= mXVInfoList.Count - 1; I++) {
if (pMoveCost2) {
CurrVal -= (mXVInfoList[I].X - CurrPos) * 2;
}
else {
CurrVal -= mXVInfoList[I].X - CurrPos;
}
CurrPos = mXVInfoList[I].X;
CurrVal += mXVInfoList[I].V;
CurrValMax = Math.Max(CurrValMax, CurrVal);
WillReturn[I] = CurrValMax;
}
return WillReturn;
}
}
解説
解候補は、下記の4通りになります。
解候補01 右にひたすら進んだ時の最大値
解候補02 左にひたすら進んだ時の最大値
解候補03 左に進んでから、原点に戻って、右に進む時の最大値
解候補04 右に進んでから、原点に戻って、左に進む時の最大値
解候補03と解候補04は、
左端と右端が同じであれば、
移動コストが2倍になる区間の違いだけ分かります。
以上により、解候補01と解候補02は、ナイーブに全探索。
解候補03は、
原点から右に進む場合の、
添字ごとの累積Maxを求めておいて、
左にどこまで進むかを全探索して、
移動コストが2倍になる区間は、2通りを試してます。