AtCoderのARC
次のARCの問題へ
前のARCの問題へ
ARC179-B Between B and B
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("3 4");
WillReturn.Add("2 1 2");
//14
}
else if (InputPattern == "Input2") {
WillReturn.Add("4 8");
WillReturn.Add("1 2 3 4");
//65536
}
else if (InputPattern == "Input3") {
WillReturn.Add("4 9");
WillReturn.Add("2 3 4 1");
//628
}
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[] wkArr = InputList[0].Split(' ').Select(pX => int.Parse(pX)).ToArray();
int M = wkArr[0];
int N = wkArr[1];
int[] XArr = InputList[1].Split(' ').Select(pX => int.Parse(pX)).ToArray();
int[] BitArr = new int[M + 1];
int BitVal = 1;
for (int I = 1; I <= M; I++) {
BitArr[I] = BitVal;
BitVal *= 2;
}
int AllBitOn = (1 << M) - 1;
// 場合の数[使用可能BitSet]
int[] PrevDP = new int[AllBitOn + 1];
PrevDP[AllBitOn] = 1;
int XArrUB = XArr.GetUpperBound(0);
for (int I = 1; I <= N; I++) {
int[] CurrDP = new int[AllBitOn + 1];
for (int J = 0; J <= AllBitOn; J++) {
if (PrevDP[J] == 0) continue;
for (int EachKey = 1; EachKey <= M; EachKey++) {
// 使用不可の場合
if ((J & BitArr[EachKey]) == 0) continue;
// 使用が必要になるもの
int NeedVal = XArr[EachKey - 1];
int NewKey = J;
if (NeedVal != EachKey) {
if ((NewKey & BitArr[EachKey]) > 0) {
NewKey -= BitArr[EachKey];
}
}
// 使用を解禁するもの
for (int K = 0; K <= XArrUB; K++) {
if (XArr[K] == EachKey) {
NewKey |= BitArr[K + 1];
}
}
CurrDP[NewKey] += PrevDP[J];
CurrDP[NewKey] %= Hou;
}
}
PrevDP = CurrDP;
}
int Answer = 0;
foreach (int EachInt in PrevDP) {
Answer += EachInt;
Answer %= Hou;
}
Console.WriteLine(Answer);
}
}
解説
場合の数[使用可能BitSet]で解いてます。
定数倍高速化で
●Dictではなく配列を使う
●配列のGetUpperBoundメソッドの結果をキャッシュする
という手法を使ってます。