AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC458-E Count 123
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 2 1");
//9
}
else if (InputPattern == "Input2") {
WillReturn.Add("5 3 4");
//204
}
else if (InputPattern == "Input3") {
WillReturn.Add("998244 998353 998107");
//701926019
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long[] GetSplitArr(string pStr)
{
return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => long.Parse(pX)).ToArray();
}
const long Hou = 998244353;
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = GetSplitArr(InputList[0]);
long X1 = wkArr[0];
long X2 = wkArr[1];
long X3 = wkArr[2];
long Answer = 0;
var InsChooseMod = new ChooseMod(X1 + X2 + X3, Hou);
// 1を置く場所を全探索
for (long I = 1; I <= X2; I++) {
if (I > X1) {
continue;
}
// 1を置く場所の選択の通り数
long SelectPattern = InsChooseMod.DeriveChoose(X2 + 1, I);
// 丸の数
long CntMaru1 = X1 - I;
// 縦棒の数
long CntTate1 = I - 1;
// 1の置き方は、重複組合せで求まる
long Pattern1 = InsChooseMod.DeriveChoose(CntMaru1 + CntTate1, CntTate1);
// 3を置ける場所
long Place3 = X2 + 1 - I;
// 3の置き方は、重複組合せで求まる
long CntMaru3 = X3;
long CntTate3 = Place3 - 1;
long Pattern3 = InsChooseMod.DeriveChoose(CntMaru3 + CntTate3, CntTate3);
long CurrPattern = 1;
CurrPattern *= SelectPattern;
CurrPattern %= Hou;
CurrPattern *= Pattern1;
CurrPattern %= Hou;
CurrPattern *= Pattern3;
CurrPattern %= Hou;
Answer += CurrPattern;
Answer %= Hou;
}
Console.WriteLine(Answer);
}
}
#region ChooseMod
// 二項係数クラス (nCr を nの最大値指定で事前準備し、高速に求める)
internal class ChooseMod
{
private long mHou;
private long[] mFacArr;
private long[] mFacInvArr;
private long[] mInvArr;
// コンストラクタ
internal ChooseMod(long pCnt, long pHou)
{
mHou = pHou;
mFacArr = new long[pCnt + 1];
mFacInvArr = new long[pCnt + 1];
mInvArr = new long[pCnt + 1];
mFacArr[0] = mFacArr[1] = 1;
mFacInvArr[0] = mFacInvArr[1] = 1;
mInvArr[1] = 1;
for (int I = 2; I <= pCnt; I++) {
mFacArr[I] = mFacArr[I - 1] * I % mHou;
mInvArr[I] = mHou - mInvArr[mHou % I] * (mHou / I) % mHou;
mFacInvArr[I] = mFacInvArr[I - 1] * mInvArr[I] % mHou;
}
}
// nCrを返す
internal long DeriveChoose(long pN, long pR)
{
if (pN < pR) return 0;
if (pN < 0 || pR < 0) return 0;
return mFacArr[pN] * (mFacInvArr[pR] * mFacInvArr[pN - pR] % mHou) % mHou;
}
}
#endregion
解説
紙とペンで考えます。
まず、2を配置し、2の前後に、連続した1か連続した3
の配置すると考えます。
□2□2□2□2□2□2□2□2□
次に、連続する1を配置する□の個数を全探索し、
選び方の通り数をchooseで求めます。
次に、1の配置の通り数を、(0を認めない)重複組合せの公式で求めます。
最後に、3の配置の通り数を、(0を認める)重複組合せの公式で求め、
積の法則で、これらを掛け算し、解くことができます。