AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC318-E Sandwiches
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("1 2 1 3 2");
//3
}
else if (InputPattern == "Input2") {
WillReturn.Add("7");
WillReturn.Add("1 2 3 4 5 6 7");
//0
}
else if (InputPattern == "Input3") {
WillReturn.Add("13");
WillReturn.Add("9 7 11 7 3 8 1 13 11 11 11 6 13");
//20
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
int[] AArr = InputList[1].Split(' ').Select(pX => int.Parse(pX)).ToArray();
// PosList[値]なDict
var PosListDict = new Dictionary<int, List<int>>();
for (int I = 0; I <= AArr.GetUpperBound(0); I++) {
if (PosListDict.ContainsKey(AArr[I]) == false) {
PosListDict[AArr[I]] = new List<int>();
}
PosListDict[AArr[I]].Add(I);
}
long Answer = 0;
foreach (var EachPair in PosListDict) {
long CurrAnswer = 0;
List<int> CurrList = EachPair.Value;
int LastInd = CurrList.Count - 1;
for (int I = 0; I <= LastInd - 1; I++) {
int CurrPos = CurrList[I];
int NextPos = CurrList[I + 1];
long SpaceRange = NextPos - CurrPos - 1;
long LeftCnt = I + 1;
long RightCnt = LastInd - I;
CurrAnswer += SpaceRange * LeftCnt * RightCnt;
}
Answer += CurrAnswer;
}
Console.WriteLine(Answer);
}
}
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>();
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
long[] AArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
long MaxVal = AArr.Max();
// 全体の件数[値]な配列
long[] EntireCntArr = new long[MaxVal + 1];
// 左の件数[値]な配列
long[] LeftCntArr = new long[MaxVal + 1];
// 左の件数 * 右の件数 [値]な配列
long[] ProdArr = new long[MaxVal + 1];
long ProdSum = 0;
foreach (long EachA in AArr) {
EntireCntArr[EachA]++;
}
long Answer = 0;
foreach (long EachA in AArr) {
// 解に計上
Answer += ProdSum - ProdArr[EachA];
// 左に移動
LeftCntArr[EachA]++;
// 再計算
ProdSum -= ProdArr[EachA];
long LeftCnt = LeftCntArr[EachA];
ProdArr[EachA] = LeftCnt * (EntireCntArr[EachA] - LeftCnt);
ProdSum += ProdArr[EachA];
}
Console.WriteLine(Answer);
}
}
解説
両端の値ごとに考える方法で、
1と両端にするとした場合に
12122122211122221
のような、1が連続してるケースに気をつける必要があります。