AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC214-F Substrings
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("abc");
//4
}
else if (InputPattern == "Input2") {
WillReturn.Add("aa");
//1
}
else if (InputPattern == "Input3") {
WillReturn.Add("acba");
//6
}
else if (InputPattern == "Input4") {
WillReturn.Add("chokudai");
//54
}
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];
S = 'S' + S; // 1文字目は番兵としてSとする
int UB = S.Length - 1;
// 登場ノードのList[文字]
var AppearIndListDict = new Dictionary<char, List<int>>();
// 遷移可能ノードのList[現在ノード]
var ToNodeListDict = new Dictionary<int, List<int>>();
for (int I = UB; 0 <= I; I--) {
char CurrChar = S[I];
if (AppearIndListDict.ContainsKey(CurrChar) == false) {
AppearIndListDict[CurrChar] = new List<int>();
}
AppearIndListDict[CurrChar].Add(I);
ToNodeListDict[I] = new List<int>();
foreach (List<int> EachAppearIndList in AppearIndListDict.Values) {
for (int J = EachAppearIndList.Count - 1; 0 <= J; J--) {
if (I > 0 && EachAppearIndList[J] <= I + 1) {
continue;
}
ToNodeListDict[I].Add(EachAppearIndList[J]);
break;
}
}
}
// 場合の数[現在ノード]なDP表
long[] DPArr = new long[UB + 1];
DPArr[0] = 1;
// 配るインラインDP
for (int I = 0; I <= UB; I++) {
foreach (int EachToNode in ToNodeListDict[I]) {
DPArr[EachToNode] += DPArr[I];
DPArr[EachToNode] %= Hou;
}
}
long Answer = 0;
for (int I = 1; I <= UB; I++) {
Answer += DPArr[I];
Answer %= Hou;
}
Console.WriteLine(Answer);
}
}
解説
ABABCという文字列で考えます。
先頭に番兵Sを追加して、
SABABCという文字列にします。
グラフや正規表現のオートマトンのような感じで、
ノードSから右方向への遷移を繰り返すとして、
Aに遷移するときは、なるべく左のAに遷移するようにする
他の文字も同様に、なるべく左の文字に遷移する。
とすれば、
遷移方法と重複のない文字列が1対1で対応するので、DPで解けます。