Topcoder SRM 358:SameDigits
定义一个函数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)
比如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;
}
}
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;
}
}