AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC181-E Transformable Teacher
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("5 3");
WillReturn.Add("1 2 3 4 7");
WillReturn.Add("1 3 8");
//3
}
else if (InputPattern == "Input2") {
WillReturn.Add("7 7");
WillReturn.Add("31 60 84 23 16 13 32");
WillReturn.Add("96 80 73 76 87 57 29");
//34
}
else if (InputPattern == "Input3") {
WillReturn.Add("15 10");
WillReturn.Add("554 525 541 814 661 279 668 360 382 175 833 783 688 793 736");
WillReturn.Add("496 732 455 306 189 207 976 73 567 759");
//239
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
long[] HArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
long[] WArr = InputList[2].Split(' ').Select(pX => long.Parse(pX)).ToArray();
int UB = HArr.GetUpperBound(0);
Array.Sort(HArr);
Array.Sort(WArr);
// 左からの奇数添字での累積和
var FromLeftRunSumDict = new Dictionary<long, long>();
// 右からの奇数添字での累積和
var FromRightRunSumDict = new Dictionary<long, long>();
long LeftRunSum = 0;
for (int I = 1; I <= UB; I += 2) {
LeftRunSum += Math.Abs(HArr[I] - HArr[I - 1]);
FromLeftRunSumDict[I] = LeftRunSum;
}
long RightRunSum = 0;
for (int I = UB - 1; 0 <= I; I -= 2) {
RightRunSum += Math.Abs(HArr[I + 1] - HArr[I]);
FromRightRunSumDict[I] = RightRunSum;
}
// Teacherは偶数添字とのみペアになれる
long Answer = long.MaxValue;
for (int I = 0; I <= HArr.GetUpperBound(0); I += 2) {
long AnswerKouho = 0;
if (I - 1 >= 0) {
AnswerKouho += FromLeftRunSumDict[I - 1];
}
if (I + 1 <= UB) {
AnswerKouho += FromRightRunSumDict[I + 1];
}
AnswerKouho += ExecSanbuntansaku(HArr[I], WArr);
Answer = Math.Min(Answer, AnswerKouho);
}
Console.WriteLine(Answer);
}
// 値を引数として、三分探索で極小値を求める
static long ExecSanbuntansaku(long pVal, long[] pWArr)
{
long L = 0;
long R = pWArr.GetUpperBound(0);
var PairHashSet = new HashSet<long>();
while (L + 1 < R) {
long C1 = (L * 2 + R) / 3;
long C2 = (L + R * 2) / 3;
long C1Val = Math.Abs(pVal - pWArr[C1]);
long C2Val = Math.Abs(pVal - pWArr[C2]);
if (C1Val < C2Val) {
R = C2;
}
else {
L = C1;
}
long Hash = L * 1000000 + R;
if (PairHashSet.Add(Hash) == false) {
break;
}
}
var MinKouhoList = new List<long>();
for (long I = L; I <= R; I++) {
long CVal = Math.Abs(pVal - pWArr[I]);
MinKouhoList.Add(CVal);
}
return MinKouhoList.Min();
}
}
解説
考察を進めると、
左からの累積和と
右からの累積和を事前にもっておき、
Teacherは、(0オリジンでの)偶数添字の生徒とのみペアになれるので、
ペアごとの最適な身長は、三分探索で求めれば良いと分かります。