「1」で始まり、最大で「1」の数字が連続するバイナリシーケンスをほぼ有効と呼びましょう。m
i = 1, ..., n
とは、正確に連続した「1」の数字で終わるj = 0, ..., m
長さa(i, j)
のほぼ有効なシーケンスの数です。i
j
それで
a(1, 1) = 1
およびa(1, j) = 0 for j != 1
、長さ 1 のほぼ有効なシーケンスは「1」だけだからです。
- なぜなら
n >= 2
、ほぼ有効な長さのシーケンスに「0」j = 0
をa(i, 0) = a(i-1, 0) + a(i-1, 1) + ... + a(i-1, m)
追加すると、「0」で終わるi-1
ほぼ有効な長さのシーケンスが得られるからです。i
- なぜなら
n >= 2
、後続のものj > 0
を持つほぼ有効a(i, j) = a(i-1, j-1)
なシーケンスに「1」を追加すると、後続のものを持つi-1
ほぼ有効な長さのシーケンスが得られるからです。j
i
最後に、必要な数はn
、末尾に「1」がある、長さのあるほぼ有効なシーケンスの数であるため、これは
f(n, m) = a(n, 1) + a(n, 2) + ... + a(n, m)
C関数として書かれています:
int a[NMAX+1][MMAX+1];
int f(int n, int m)
{
int i, j, s;
// compute a(1, j):
for (j = 0; j <= m; j++)
a[1][j] = (j == 1);
for (i = 2; i <= n; i++) {
// compute a(i, 0):
s = 0;
for (j = 0; j <= m; j++)
s += a[i-1][j];
a[i][0] = s;
// compute a(i, j):
for (j = 1; j <= m; j++)
a[i][j] = a[i-1][j-1];
}
// final result:
s = 0;
for (j = 1; j <= m; j++)
s += a[n][j];
return s;
}
行列の最後の列のみa
が必要なため、ストレージ要件はさらに改善される可能性があります。ランタイムの複雑さはO(n*m)
.