トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
Problem113 非はずみ数
問題
ある数の桁を左から右へと順に見たとき, 任意の桁の数が自身の左にある桁の数以上であるとき,
その数を増加数 (increasing number) と呼ぶ;
例えば134468は増加数である.
同様に, 任意の桁の数が自身の右にある桁の数以上であるとき,
その数を減少数 (decreasing number) と呼ぶ;
例えば66420がそうである.
増加数でも減少数でもない正の整数を "はずみ"数 ("bouncy" number) と呼ぶ;
155349がそうである.
nが大きくなるにつれ, n以下のはずみ数の割合は大きくなる.
例えば, 100万未満では, はずみ数でない数は12951個しかない.
同様に, 100億未満では277032個しかない.
googol数 (10の100乗) 未満ではずみ数でない数の個数を答えよ.
ソース
using System;
using System.Linq;
class Program
{
static void Main()
{
Solve(6);
Solve(10);
Solve(100);
}
static void Solve(int pKetaSuuJyougen)
{
Console.WriteLine("{0}桁未満の数で検証します。", pKetaSuuJyougen);
long ZoukasuuCnt = DeriveZoukasuuCnt(pKetaSuuJyougen);
long GensyousuuCnt = DeriveGensyousuuCnt(pKetaSuuJyougen);
Console.WriteLine("増加数は、{0}個", ZoukasuuCnt);
Console.WriteLine("減少数は、{0}個", GensyousuuCnt);
int KyoutuuCnt = 9 * pKetaSuuJyougen;
Console.WriteLine("増加数かつ減少数は、{0}個", KyoutuuCnt);
Console.WriteLine("非はずみ数は、{0}個", ZoukasuuCnt + GensyousuuCnt - KyoutuuCnt);
Console.WriteLine();
}
//増加数の個数を求める
static long DeriveZoukasuuCnt(int pKetaSuuJyougen)
{
//場合の数[現在の桁の数字]なDP表
long[] PrevDP = new long[10];
for (int I = 1; I <= 9; I++)
PrevDP[I] = 1;
long WillReturn = PrevDP.Sum();
for (int I = 2; I <= pKetaSuuJyougen; I++) {
long[] CurrDP = new long[10];
for (int J = 1; J <= 9; J++) {
if (PrevDP[J] == 0) continue;
for (int K = J; K <= 9; K++)
CurrDP[K] += PrevDP[J];
}
WillReturn += CurrDP.Sum();
PrevDP = CurrDP;
}
return WillReturn;
}
//減少数の個数を求める
static long DeriveGensyousuuCnt(int pKetaSuuJyougen)
{
//場合の数[現在の桁の数字]なDP表
long[] PrevDP = new long[10];
long WillReturn = 0;
for (int I = 1; I <= 9; I++) {
PrevDP[I] = 1;
//減少数は、右に0を付加した分も計上する
int RestKetaSuu = pKetaSuuJyougen - 1;
WillReturn += 1 + RestKetaSuu;
}
for (int I = 2; I <= pKetaSuuJyougen; I++) {
long[] CurrDP = new long[10];
for (int J = 1; J <= 9; J++) {
if (PrevDP[J] == 0) continue;
for (int K = J; 1 <= K; K--)
CurrDP[K] += PrevDP[J];
}
foreach (long EachLong in CurrDP) {
//減少数は、右に0を付加した分も計上する
int RestKetaSuu = pKetaSuuJyougen - I;
WillReturn += EachLong * (RestKetaSuu + 1);
}
PrevDP = CurrDP;
}
return WillReturn;
}
}
実行結果
6桁未満の数で検証します。
増加数は、5004個
減少数は、8001個
増加数かつ減少数は、54個
非はずみ数は、12951個
10桁未満の数で検証します。
増加数は、92377個
減少数は、184745個
増加数かつ減少数は、90個
非はずみ数は、277032個
100桁未満の数で検証します。
増加数は、4263421511270個
減少数は、46897636623880個
増加数かつ減少数は、900個
非はずみ数は、51161058134250個
解説
個数定理
n(A∪B) = n(A) + n(B) - n(A∩B)
をふまえて
桁DPで、増加数と減少数の個数を求めてから、
増加数かつ減少数の個数を引いてます。