AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC262-E Red and Blue Graph
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("4 4 2");
WillReturn.Add("1 2");
WillReturn.Add("1 3");
WillReturn.Add("2 3");
WillReturn.Add("3 4");
//2
}
else if (InputPattern == "Input2") {
WillReturn.Add("10 10 3");
WillReturn.Add("1 2");
WillReturn.Add("2 4");
WillReturn.Add("1 5");
WillReturn.Add("3 6");
WillReturn.Add("3 9");
WillReturn.Add("4 10");
WillReturn.Add("7 8");
WillReturn.Add("9 10");
WillReturn.Add("5 9");
WillReturn.Add("3 4");
//64
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
const long Hou = 998244353;
static long mN;
static long mK;
// 隣接リスト
static Dictionary<long, List<long>> mToNodeListDict = new Dictionary<long, List<long>>();
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();
SplitAct(InputList[0]);
mN = wkArr[0];
mK = wkArr[2];
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
long FromNode = wkArr[0];
long ToNode = wkArr[1];
if (mToNodeListDict.ContainsKey(FromNode) == false) {
mToNodeListDict[FromNode] = new List<long>();
}
if (mToNodeListDict.ContainsKey(ToNode) == false) {
mToNodeListDict[ToNode] = new List<long>();
}
mToNodeListDict[FromNode].Add(ToNode);
mToNodeListDict[ToNode].Add(FromNode);
}
// 次数が奇数のノード数
long OddNodeCnt = 0;
foreach (var EachPair in mToNodeListDict) {
if (EachPair.Value.Count % 2 == 1) {
OddNodeCnt++;
}
}
// 次数が偶数のノード数
long EvenNodeCnt = mN - OddNodeCnt;
var InsChooseMod = new ChooseMod(mN, Hou);
long Answer = 0;
for (long I = 0; I <= mK; I += 2) {
if (I > OddNodeCnt) break;
long PatternCnt = InsChooseMod.DeriveChoose(OddNodeCnt, I);
long RestNeed = mK - I;
if (RestNeed > 0) {
PatternCnt *= InsChooseMod.DeriveChoose(EvenNodeCnt, RestNeed);
PatternCnt %= Hou;
}
Answer += PatternCnt;
Answer %= Hou;
}
Console.WriteLine(Answer);
}
}
#region ChooseMod
// 二項係数クラス
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
解説
全てのノードが最初は青色で
K個のノードを赤色に塗る場合の数を考えます。
(青ノードとの隣接数 , 赤ノードとの隣接数) で場合分けして考えます。
(0,1)
(0,2)
(0,3)
(1,0)
(1,1)
(1,2)
(1,3)
(2,0)
(2,1)
(2,2)
(2,3)
異なる色で塗られたノード数 mod 2
は、mod 2 の世界なので
足し算と引き算は、同じことになります。
なので、次数が奇数のノードを偶数個選べば
異なる色で塗られたノード数 mod 2
は0になります。
後は、次数が奇数のノードを偶数個選んでから
次数が偶数のノードを、残りの選択数分選ぶ方法
を積の法則で求めれば良いです。