AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC268-E Chinese Restaurant (Three-Star Version)
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("4");
WillReturn.Add("1 2 0 3");
//2
}
else if (InputPattern == "Input2") {
WillReturn.Add("3");
WillReturn.Add("0 1 2");
//0
}
else if (InputPattern == "Input3") {
WillReturn.Add("10");
WillReturn.Add("3 9 6 1 7 2 8 0 5 4");
//20
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
int[] pArr = InputList[1].Split(' ').Select(pX => int.Parse(pX)).ToArray();
int UB = pArr.GetUpperBound(0);
int Len = pArr.Length;
int MaxDistance = Len / 2;
long[] RunSumArr = new long[Len * 2];
long CurrScore = 0;
for (int I = 0; I <= UB; I++) {
int CurrVal = pArr[I];
var GoalIndList = new List<int>();
GoalIndList.Add(CurrVal - Len * 2);
GoalIndList.Add(CurrVal - Len);
GoalIndList.Add(CurrVal);
GoalIndList.Add(CurrVal + Len);
GoalIndList.Add(CurrVal + Len * 2);
CurrScore += GoalIndList.Min(pX => Math.Abs(I - pX));
var RangeInfoList = new List<RangeInfoDef>();
int CurrInd = I;
int IndLimit = I + Len;
while (CurrInd < IndLimit) {
int CurrDistance = GoalIndList.Min(pX => Math.Abs(CurrInd - pX));
int NextDistance = GoalIndList.Min(pX => Math.Abs(CurrInd + 1 - pX));
// 減少か変わらなかったら、0まで減少
if (CurrDistance >= NextDistance) {
RangeInfoDef WillAdd1;
WillAdd1.RangeStaInd = CurrInd + 1;
WillAdd1.RangeEndInd = CurrInd + 1;
WillAdd1.Kaisa = NextDistance - CurrDistance;
RangeInfoList.Add(WillAdd1);
if (NextDistance > 0) {
RangeInfoDef WillAdd2;
WillAdd2.RangeStaInd = CurrInd + 2;
WillAdd2.RangeEndInd = WillAdd2.RangeStaInd + NextDistance - 1;
WillAdd2.Kaisa = -1;
RangeInfoList.Add(WillAdd2);
CurrInd = WillAdd2.RangeEndInd;
}
else {
CurrInd = WillAdd1.RangeEndInd;
}
}
// 増加したら、最大値まで増加
if (CurrDistance < NextDistance) {
RangeInfoDef WillAdd1;
WillAdd1.RangeStaInd = CurrInd + 1;
WillAdd1.RangeEndInd = CurrInd + 1;
WillAdd1.Kaisa = 1;
RangeInfoList.Add(WillAdd1);
if (NextDistance < MaxDistance) {
RangeInfoDef WillAdd2;
WillAdd2.RangeStaInd = CurrInd + 2;
WillAdd2.RangeEndInd = WillAdd2.RangeStaInd + MaxDistance - NextDistance - 1;
WillAdd2.Kaisa = 1;
RangeInfoList.Add(WillAdd2);
CurrInd = WillAdd2.RangeEndInd;
}
else {
CurrInd = WillAdd1.RangeEndInd;
}
}
}
foreach (RangeInfoDef EachRangeInfo in RangeInfoList) {
int ImosSta = EachRangeInfo.RangeStaInd - I;
int ImosEnd = EachRangeInfo.RangeEndInd - I + 1;
RunSumArr[ImosSta] += EachRangeInfo.Kaisa;
if (ImosEnd <= UB) {
RunSumArr[ImosEnd] -= EachRangeInfo.Kaisa;
}
}
}
long Answer = CurrScore;
for (int I = 1; I <= UB; I++) {
RunSumArr[I] += RunSumArr[I - 1];
CurrScore += RunSumArr[I];
Answer = Math.Min(Answer, CurrScore);
}
Console.WriteLine(Answer);
}
struct RangeInfoDef
{
internal int Kaisa;
internal int RangeStaInd;
internal int RangeEndInd;
}
}
解説
料理ごとに1つ右に回転した時の不満度の差分を考えれば、
階差数列で考えることができます。
後は、階差数列の値と区間を考えて、いもす法で解くことができます。