AtCoderのARC
次のARCの問題へ
前のARCの問題へ
ARC135-B Sum of Three Terms
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");
WillReturn.Add("6 9 6 6 5");
//Yes
//0 4 2 3 1 2 2
}
else if (InputPattern == "Input2") {
WillReturn.Add("5");
WillReturn.Add("0 1 2 1 0");
//No
}
else if (InputPattern == "Input3") {
WillReturn.Add("1");
WillReturn.Add("10");
//Yes
//0 0 10
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
long[] SArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
long[] AnswerArr = new long[SArr.Length + 2];
// mod 3 で 0の場所の値を決める
var ValSet = new HashSet<long>();
AnswerArr[0] = 0;
ValSet.Add(0);
for (int I = 3; I <= AnswerArr.GetUpperBound(0); I += 3) {
AnswerArr[I] = AnswerArr[I - 3] + SArr[I - 2] - SArr[I - 3];
ValSet.Add(AnswerArr[I]);
}
if (ValSet.Min() < 0) {
long Geta = Math.Abs(ValSet.Min());
for (int I = 0; I <= AnswerArr.GetUpperBound(0); I += 3) {
AnswerArr[I] += Geta;
}
}
// mod 3 で 1の場所の値を決める
ValSet.Clear();
AnswerArr[1] = 0;
ValSet.Add(0);
for (int I = 4; I <= AnswerArr.GetUpperBound(0); I += 3) {
AnswerArr[I] = AnswerArr[I - 3] + SArr[I - 2] - SArr[I - 3];
ValSet.Add(AnswerArr[I]);
}
if (ValSet.Min() < 0) {
long Geta = Math.Abs(ValSet.Min());
for (int I = 1; I <= AnswerArr.GetUpperBound(0); I += 3) {
AnswerArr[I] += Geta;
}
}
// mod 3 で 2の場所の値を決める
for (int I = 2; I <= AnswerArr.GetUpperBound(0); I += 3) {
AnswerArr[I] = SArr[I - 2] - AnswerArr[I - 2] - AnswerArr[I - 1];
}
// 十分性のチェック
bool IsOK = true;
if (Array.Exists(AnswerArr, pX => pX < 0)) {
IsOK = false;
}
for (int I = 2; I <= AnswerArr.GetUpperBound(0); I++) {
long Sum = AnswerArr[I - 2] + AnswerArr[I - 1] + AnswerArr[I];
if (Sum != SArr[I - 2]) {
IsOK = false;
}
}
if (IsOK) {
Console.WriteLine("Yes");
// セパレータとLong型の列挙を引数として、結合したstringを返す
Func<string, IEnumerable<long>, string> LongEnumJoin = (pSeparater, pEnum) =>
{
string[] StrArr = Array.ConvertAll(pEnum.ToArray(), pX => pX.ToString());
return string.Join(pSeparater, StrArr);
};
Console.WriteLine(LongEnumJoin(" ", AnswerArr));
}
else {
Console.WriteLine("No");
}
}
}
解説
6 9 6 6 5
で考えます。
6 9 6 6 5
A B C D E F G
という図を書くと
A+B+C = 6
B+C+D = 9
C+D+E = 6
D+E+F = 6
E+F+G = 5
が成り立つと分かります。
Aを0に仮決めすると
添え字の3つ飛ばしでDとGを決定できます。
Bを0に仮決めすると
添え字の3つ飛ばしでEを決定できます。
負数がNGなので
Aを0に仮決めした際に、
DかGに負数が発生したら、
A,D,Gに負数の絶対値を足して、
負数を防ぎます。
Bを0に仮決めした際に、
Eが負数になったら、
B,Eに負数の絶対値を足して、
負数を防ぎます。
AとBが決定したら、残りの数も決まるので
全ての数を仮決めします。
最後に十分性を確認すれば、解が求まります。