トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
Problem679 各文字列が1回ずつ現れる文字列の個数
問題
長さnで A, E, F, R からなる文字列のうち、
4つのキーワード FREE, FARE, AREA, REEF を各1回ずつ含むものはいくつあるか。
n=30について求めよ。
ソース
using System;
using System.Collections.Generic;
class Program
{
struct JyoutaiDef
{
internal bool AppearFREE;
internal bool AppearFARE;
internal bool AppearAREA;
internal bool AppearREEF;
internal string Last4Str;
}
//ハッシュ値をJyoutaiDef型に変換
static JyoutaiDef HashToJyoutai(string pHash)
{
JyoutaiDef WillReturn;
WillReturn.AppearFREE = (pHash[0] == '1');
WillReturn.AppearFARE = (pHash[1] == '1');
WillReturn.AppearAREA = (pHash[2] == '1');
WillReturn.AppearREEF = (pHash[3] == '1');
WillReturn.Last4Str = pHash.Substring(4);
return WillReturn;
}
//JyoutaiDef型をハッシュ値に変換
static string JyoutaiToHash(JyoutaiDef pJyoutai)
{
string WillReturn = "";
WillReturn += (pJyoutai.AppearFREE ? "1" : "0");
WillReturn += (pJyoutai.AppearFARE ? "1" : "0");
WillReturn += (pJyoutai.AppearAREA ? "1" : "0");
WillReturn += (pJyoutai.AppearREEF ? "1" : "0");
WillReturn += pJyoutai.Last4Str;
return WillReturn;
}
static void Main()
{
Solve(9);
Solve(15);
Solve(30);
}
static void Solve(int pN)
{
//場合の数[状態のハッシュ値]なDP表
var PrevDP = new Dictionary<string, long>();
PrevDP["0000"] = 1;
for (int I = 1; I <= pN; I++) {
var CurrDP = new Dictionary<string, long>();
foreach (var EachPair in PrevDP) {
JyoutaiDef OldJyoutai = HashToJyoutai(EachPair.Key);
foreach (char EachChar in "AEFR") {
JyoutaiDef NewJyoutai = OldJyoutai;
NewJyoutai.Last4Str += EachChar.ToString();
if (NewJyoutai.Last4Str.Length > 4) {
NewJyoutai.Last4Str = NewJyoutai.Last4Str.Substring(1, 4);
}
if (NewJyoutai.Last4Str == "FREE") {
if (OldJyoutai.AppearFREE) continue;
NewJyoutai.AppearFREE = true;
}
if (NewJyoutai.Last4Str == "FARE") {
if (OldJyoutai.AppearFARE) continue;
NewJyoutai.AppearFARE = true;
}
if (NewJyoutai.Last4Str == "AREA") {
if (OldJyoutai.AppearAREA) continue;
NewJyoutai.AppearAREA = true;
}
if (NewJyoutai.Last4Str == "REEF") {
if (OldJyoutai.AppearREEF) continue;
NewJyoutai.AppearREEF = true;
}
string NewHash = JyoutaiToHash(NewJyoutai);
if (CurrDP.ContainsKey(NewHash))
CurrDP[NewHash] += EachPair.Value;
else CurrDP[NewHash] = EachPair.Value;
}
}
PrevDP = CurrDP;
}
long Answer = 0;
foreach (var EachPair in PrevDP) {
if (EachPair.Key.StartsWith("1111")) {
Answer += EachPair.Value;
}
}
Console.WriteLine("N={0}だと{1}通り", pN, Answer);
}
}
実行結果
N=9だと1通り
N=15だと72863通り
N=30だと644997092988678通り
解説
"FREE"、"FARE"、"AREA"、"REEF"の登場有無と、
末尾4文字を状態に持って、動的計画法で解いてます。