using System;
using System.Collections.Generic;
class Program
{
static int UB;
static void Main()
{
Solve(10M);
Solve(10000000000000000000000000M);
}
static void Solve(decimal pN)
{
string BinStr = DeriveBinStr(pN);
UB = BinStr.Length - 1;
//場合の数[現在の数値]なDP表
var PrevDP = new Dictionary<string, long>();
PrevDP.Add(BinStr.Replace('1', '0'), 1);
for (int I = UB; 0 <= I; I--) {
var CurrDP = new Dictionary<string, long>();
foreach (var EachPair in PrevDP) {
Action<string> MergeAct = (pNewKey) =>
{
//枝切り処理
if (BinStr[I] != pNewKey[I]) return;
if (CurrDP.ContainsKey(pNewKey)) {
CurrDP[pNewKey] += EachPair.Value;
}
else CurrDP[pNewKey] = EachPair.Value;
};
//0回加算のケース
string NewKey0 = EachPair.Key;
MergeAct(NewKey0);
//1回加算のケース
bool IsOverFlow1;
string NewKey1 = ExecKasan(EachPair.Key, I, out IsOverFlow1);
if (IsOverFlow1 == false) MergeAct(NewKey1);
//2回加算のケース
if (I > 0) {
bool IsOverFlow2;
string NewKey2 = ExecKasan(EachPair.Key, I - 1, out IsOverFlow2);
if (IsOverFlow2 == false) MergeAct(NewKey2);
}
}
Console.WriteLine("右から{0}桁目のDP結果", UB - I + 1);
foreach (var EachPair in CurrDP) {
Console.WriteLine("CurrDP[{0}]={1}", EachPair.Key, EachPair.Value);
}
PrevDP = CurrDP;
}
Console.WriteLine("f({0})={1}", pN, PrevDP[BinStr]);
}
//2進数にしたString型を返す
static string DeriveBinStr(decimal pN)
{
var ModList = new List<int>();
decimal CopiedVal = pN;
do {
if (CopiedVal % 2 == 0) {
ModList.Add(0);
CopiedVal /= 2;
}
else {
ModList.Add(1);
CopiedVal = (CopiedVal - 1) / 2;
}
} while (CopiedVal > 0);
ModList.Reverse();
var sb = new System.Text.StringBuilder();
ModList.ForEach(X => sb.Append(X));
return sb.ToString();
}
//加算処理
static string ExecKasan(string pStr, int pPos, out bool pIsOverFlow)
{
pIsOverFlow = false;
char[] wkArr = pStr.ToCharArray();
wkArr[pPos]++;
//繰り上がりの処理
for (int I = pPos; 0 <= I; I--) {
if (wkArr[I] == '2') {
if (I == 0) {
pIsOverFlow = true;
break;
}
wkArr[I] = '0';
wkArr[I - 1]++;
}
else break;
}
return new string(wkArr);
}
}