定义一个函数f(n)表示中最长的一个序列,这个序列有相同的数字组成。
比如f(344488)=3,f(123)=1
现在给定两个整数n,k要求出有多少个数x,满足x的位数不大于n且f(x)=k.由于结果会很大,只用求出结果mod 44444444的值就可以了。
先考虑有多少个n位数x,满足f(x)=k.
我们从左往右来天数,需要记录的状态信息是:
1)有多少位数字要填
2) 此前填的数字末尾有多少位是相同的
3) 此前填的数字是否已经达到了要求(即最长的连续相同的数字序列长度为k)
我们记此状态为f(n,last_same,did_reach),这样很容易建立递推关系。
那么,刚好为n位数的结果就是9*f(n-1,1,false)
public
class
SameDigits {
final
static
long
MOD
=
44444444
;
long
[][][] memo;
int
K;
long
f(
int
n,
int
last_same,
int
did_reach ){
if
( memo[n][last_same][did_reach]
!=
-
1
)
return
memo[n][last_same][did_reach];
if
( n
==
0
){
if
( did_reach
==
1
||
last_same
==
K ) {
return
memo[n][last_same][did_reach]
=
1
;
}
else
{
return
memo[n][last_same][did_reach]
=
0
;
}
}
if
( k
==
K )
return
memo[n][last_same][did_reach]
=
(
9
*
f( n
-
1
,
1
,
1
) )
%
MOD;
return
memo[n][last_same][did_reach]
=
( f( n
-
1
, k
+
1
, did_reach )
+
9
*
f( n
-
1
,
1
, did_reach ) )
%
MOD;
}
public
int
howMany(
int
n,
int
k ) {
K
=
k;
memo
=
new
long
[ n
+
1
][ k
+
1
][
2
];
for
(
int
i
=
0
; i
<
memo.length;
++
i )
for
(
int
j
=
0
; j
<
memo[i].length;
++
j ) Arrays.fill( memo[i][j],
-
1
);
long
sol
=
0
;
for
(
int
i
=
k; i
<=
n;
++
i ){
sol
=
(sol
+
9
*
f( i
-
1
,
1
,
0
))
%
MOD;
}
return
(
int
)sol;
}
}