AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC104-D We Love ABC
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("A??C");
//8
}
else if (InputPattern == "Input2") {
WillReturn.Add("ABCBC");
//3
}
else if (InputPattern == "Input3") {
WillReturn.Add("????C?????B??????A???????");
//979596887
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
const long Hou = 1000000007;
static void Main()
{
List<string> InputList = GetInputList();
string S = InputList[0];
// 下記の状態番号で状態を管理
// 状態0 文字を未選択
// 状態1 文字Aを選択
// 状態2 文字ABを選択
// 状態3 文字ABCを選択
// 場合の数[状態番号]なDP表
long[] PrevDP = new long[4];
PrevDP[0] = 1;
foreach (char CurrChar in S) {
long[] CurrDP = new long[4];
for (int I = 0; I <= 3; I++) {
if (PrevDP[I] == 0) continue;
// 状態を維持する経路
if (CurrChar == '?') {
CurrDP[I] += PrevDP[I] * 3;
}
else {
CurrDP[I] += PrevDP[I];
}
CurrDP[I] %= Hou;
// 次の状態に遷移する経路
if (I == 0 && (CurrChar == 'A' || CurrChar == '?')) {
CurrDP[1] += PrevDP[0];
}
if (I == 1 && (CurrChar == 'B' || CurrChar == '?')) {
CurrDP[2] += PrevDP[1];
}
if (I == 2 && (CurrChar == 'C' || CurrChar == '?')) {
CurrDP[3] += PrevDP[2];
}
CurrDP[I] %= Hou;
}
PrevDP = CurrDP;
}
Console.WriteLine(PrevDP[3]);
}
}
解説
下記の状態番号で状態を管理するとし、
状態0 文字を未選択
状態1 文字Aを選択
状態2 文字ABを選択
状態3 文字ABCを選択
ABC?ACという文字列が入力されるとして、
空文字
A
AB
ABC?
ABC?A
ABC?AC
という順序で、1文字ずつ文字を処理したときの下記の場合の数の遷移をふまえて、
動的計画法を使ってます。
N A B C ? A C
0 1 1 1 1 3 3 3
1 0 1 1 1 4 7 7
2 0 0 1 1 4 4 4
3 0 0 0 1 4 4 8