AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC222-D Between Two Arrays
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("2");
WillReturn.Add("1 1");
WillReturn.Add("2 3");
//5
}
else if (InputPattern == "Input2") {
WillReturn.Add("3");
WillReturn.Add("2 2 2");
WillReturn.Add("2 2 2");
//1
}
else if (InputPattern == "Input3") {
WillReturn.Add("10");
WillReturn.Add("1 2 3 4 5 6 7 8 9 10");
WillReturn.Add("1 4 9 16 25 36 49 64 81 100");
//978222082
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
const int Hou = 998244353;
static void Main()
{
List<string> InputList = GetInputList();
int[] AArr = InputList[1].Split(' ').Select(pX => int.Parse(pX)).ToArray();
int[] BArr = InputList[2].Split(' ').Select(pX => int.Parse(pX)).ToArray();
int UB = AArr.GetUpperBound(0);
// 場合の数[直近の値]なDP表
int[] PrevDP = new int[3000 + 1];
PrevDP[0] = 1;
for (int I = 0; I <= UB; I++) {
int[] CurrDP = new int[3000 + 1];
for (int J = 0; J <= CurrDP.GetUpperBound(0); J++) {
if (PrevDP[J] == 0) continue;
// 配るDPで配れる区間を求め、いもす法で配る
int RangeMin = AArr[I];
int RangeMax = BArr[I];
if (RangeMin > RangeMax) continue;
if (J <= RangeMax) {
RangeMin = Math.Max(RangeMin, J);
CurrDP[RangeMin] += PrevDP[J];
CurrDP[RangeMin] %= Hou;
if (RangeMax + 1 <= CurrDP.GetUpperBound(0)) {
CurrDP[RangeMax + 1] -= PrevDP[J];
CurrDP[RangeMax + 1] %= Hou;
}
}
}
// いもす法の累積和を求める
for (int J = 1; J <= CurrDP.GetUpperBound(0); J++) {
CurrDP[J] += CurrDP[J - 1];
CurrDP[J] %= Hou;
if (CurrDP[J] < 0) CurrDP[J] += Hou;
}
PrevDP = CurrDP;
}
int Answer = 0;
foreach (int EachInt in PrevDP) {
Answer += EachInt;
Answer %= Hou;
}
Console.WriteLine(Answer);
}
}
解説
配るDPですが、いもす法で配ってます。