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)

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;
    }
}


你可能感兴趣的:(topcoder)